/******************************************************************************
 *
 *  Copyright (C) 1999-2014 Broadcom Corporation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at:
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 ******************************************************************************/

/******************************************************************************
 *
 *  This file contains functions that handle inquiries. These include
 *  setting discoverable mode, controlling the mode of the Baseband, and
 *  maintaining a small database of inquiry responses, with API for people
 *  to browse it.
 *
 ******************************************************************************/

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stddef.h>

#include "gki.h"
#include "osi/include/osi.h"

#include "bt_types.h"
#include "bt_common.h"
#include "hcimsgs.h"
#include "btu.h"
#include "btm_api.h"
#include "btm_int.h"
#include "hcidefs.h"

/* 3 second timeout waiting for responses */
#define BTM_INQ_REPLY_TIMEOUT_MS (3 * 1000)

/* TRUE to enable DEBUG traces for btm_inq */
#ifndef BTM_INQ_DEBUG
    #define BTM_INQ_DEBUG   FALSE
#endif

#ifdef USE_ALARM
    extern fixed_queue_t *btu_general_alarm_queue;
#endif

/********************************************************************************/
/*                 L O C A L    D A T A    D E F I N I T I O N S                */
/********************************************************************************/
static const LAP general_inq_lap = {0x9e, 0x8b, 0x33};
static const LAP limited_inq_lap = {0x9e, 0x8b, 0x00};

const uint16_t BTM_EIR_UUID_LKUP_TBL[BTM_EIR_MAX_SERVICES] =
{
    UUID_SERVCLASS_SERVICE_DISCOVERY_SERVER,
    /*    UUID_SERVCLASS_BROWSE_GROUP_DESCRIPTOR,   */
    /*    UUID_SERVCLASS_PUBLIC_BROWSE_GROUP,       */
    UUID_SERVCLASS_SERIAL_PORT,
    UUID_SERVCLASS_LAN_ACCESS_USING_PPP,
    UUID_SERVCLASS_DIALUP_NETWORKING,
    UUID_SERVCLASS_IRMC_SYNC,
    UUID_SERVCLASS_OBEX_OBJECT_PUSH,
    UUID_SERVCLASS_OBEX_FILE_TRANSFER,
    UUID_SERVCLASS_IRMC_SYNC_COMMAND,
    UUID_SERVCLASS_HEADSET,
    UUID_SERVCLASS_CORDLESS_TELEPHONY,
    UUID_SERVCLASS_AUDIO_SOURCE,
    UUID_SERVCLASS_AUDIO_SINK,
    UUID_SERVCLASS_AV_REM_CTRL_TARGET,
    /*    UUID_SERVCLASS_ADV_AUDIO_DISTRIBUTION,    */
    UUID_SERVCLASS_AV_REMOTE_CONTROL,
    /*    UUID_SERVCLASS_VIDEO_CONFERENCING,        */
    UUID_SERVCLASS_INTERCOM,
    UUID_SERVCLASS_FAX,
    UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY,
    /*    UUID_SERVCLASS_WAP,                       */
    /*    UUID_SERVCLASS_WAP_CLIENT,                */
    UUID_SERVCLASS_PANU,
    UUID_SERVCLASS_NAP,
    UUID_SERVCLASS_GN,
    UUID_SERVCLASS_DIRECT_PRINTING,
    /*    UUID_SERVCLASS_REFERENCE_PRINTING,        */
    UUID_SERVCLASS_IMAGING,
    UUID_SERVCLASS_IMAGING_RESPONDER,
    UUID_SERVCLASS_IMAGING_AUTO_ARCHIVE,
    UUID_SERVCLASS_IMAGING_REF_OBJECTS,
    UUID_SERVCLASS_HF_HANDSFREE,
    UUID_SERVCLASS_AG_HANDSFREE,
    UUID_SERVCLASS_DIR_PRT_REF_OBJ_SERVICE,
    /*    UUID_SERVCLASS_REFLECTED_UI,              */
    UUID_SERVCLASS_BASIC_PRINTING,
    UUID_SERVCLASS_PRINTING_STATUS,
    UUID_SERVCLASS_HUMAN_INTERFACE,
    UUID_SERVCLASS_CABLE_REPLACEMENT,
    UUID_SERVCLASS_HCRP_PRINT,
    UUID_SERVCLASS_HCRP_SCAN,
    /*    UUID_SERVCLASS_COMMON_ISDN_ACCESS,        */
    /*    UUID_SERVCLASS_VIDEO_CONFERENCING_GW,     */
    /*    UUID_SERVCLASS_UDI_MT,                    */
    /*    UUID_SERVCLASS_UDI_TA,                    */
    /*    UUID_SERVCLASS_VCP,                       */
    UUID_SERVCLASS_SAP,
    UUID_SERVCLASS_PBAP_PCE,
    UUID_SERVCLASS_PBAP_PSE,
    UUID_SERVCLASS_PHONE_ACCESS,
    UUID_SERVCLASS_HEADSET_HS,
    UUID_SERVCLASS_PNP_INFORMATION,
    /*    UUID_SERVCLASS_GENERIC_NETWORKING,        */
    /*    UUID_SERVCLASS_GENERIC_FILETRANSFER,      */
    /*    UUID_SERVCLASS_GENERIC_AUDIO,             */
    /*    UUID_SERVCLASS_GENERIC_TELEPHONY,         */
    /*    UUID_SERVCLASS_UPNP_SERVICE,              */
    /*    UUID_SERVCLASS_UPNP_IP_SERVICE,           */
    /*    UUID_SERVCLASS_ESDP_UPNP_IP_PAN,          */
    /*    UUID_SERVCLASS_ESDP_UPNP_IP_LAP,          */
    /*    UUID_SERVCLASS_ESDP_UPNP_IP_L2CAP,        */
    UUID_SERVCLASS_VIDEO_SOURCE,
    UUID_SERVCLASS_VIDEO_SINK,
    /*    UUID_SERVCLASS_VIDEO_DISTRIBUTION         */
    UUID_SERVCLASS_MESSAGE_ACCESS,
    UUID_SERVCLASS_MESSAGE_NOTIFICATION,
    UUID_SERVCLASS_HDP_SOURCE,
    UUID_SERVCLASS_HDP_SINK
};

/********************************************************************************/
/*              L O C A L    F U N C T I O N     P R O T O T Y P E S            */
/********************************************************************************/
static void         btm_initiate_inquiry(tBTM_INQUIRY_VAR_ST *p_inq);
static tBTM_STATUS  btm_set_inq_event_filter(uint8_t filter_cond_type, tBTM_INQ_FILT_COND *p_filt_cond);
static void         btm_clr_inq_result_flt(void);

static uint8_t        btm_convert_uuid_to_eir_service(uint16_t uuid16);
static void         btm_set_eir_uuid(uint8_t *p_eir, tBTM_INQ_RESULTS *p_results);
static uint8_t       *btm_eir_get_uuid_list(uint8_t *p_eir, uint8_t uuid_size,
        uint8_t *p_num_uuid, uint8_t *p_uuid_list_type);
static uint16_t       btm_convert_uuid_to_uuid16(uint8_t *p_uuid, uint8_t uuid_size);

/*******************************************************************************
**
** Function         BTM_SetDiscoverability
**
** Description      This function is called to set the device into or out of
**                  discoverable mode. Discoverable mode means inquiry
**                  scans are enabled.  If a value of '0' is entered for window or
**                  interval, the default values are used.
**
** Returns          BTM_SUCCESS if successful
**                  BTM_BUSY if a setting of the filter is already in progress
**                  BTM_NO_RESOURCES if couldn't get a memory pool buffer
**                  BTM_ILLEGAL_VALUE if a bad parameter was detected
**                  BTM_WRONG_MODE if the device is not up.
**
*******************************************************************************/
tBTM_STATUS BTM_SetDiscoverability(uint16_t inq_mode, uint16_t window, uint16_t interval)
{
    uint8_t        scan_mode = 0;
    uint16_t       service_class;
    uint8_t       *p_cod;
    uint8_t        major, minor;
    DEV_CLASS    cod;
    LAP          temp_lap[2];
    uint8_t      is_limited;
    uint8_t      cod_limited;
    BTM_TRACE_API("BTM_SetDiscoverability\r\n");
    #if (BLE_INCLUDED == TRUE && BLE_INCLUDED == TRUE)

    if(HCI_LE_HOST_SUPPORTED(btm_cb.devcb.local_lmp_features[HCI_EXT_FEATURES_PAGE_1]))
    {
        if(btm_ble_set_discoverability((uint16_t)(inq_mode))
                == BTM_SUCCESS)
        {
            btm_cb.btm_inq_vars.discoverable_mode &= (~BTM_BLE_DISCOVERABLE_MASK);
            btm_cb.btm_inq_vars.discoverable_mode |= (inq_mode & BTM_BLE_DISCOVERABLE_MASK);
        }
    }

    inq_mode &= ~BTM_BLE_DISCOVERABLE_MASK;
    #endif

    /*** Check mode parameter ***/
    if(inq_mode > BTM_MAX_DISCOVERABLE)
    {
        return (BTM_ILLEGAL_VALUE);
    }

    /* Make sure the controller is active */
    if(btm_cb.devcb.state < BTM_DEV_STATE_READY)
    {
        return (BTM_DEV_RESET);
    }

    /* If the window and/or interval is '0', set to default values */
    if(!window)
    {
        window = BTM_DEFAULT_DISC_WINDOW;
    }

    if(!interval)
    {
        interval = BTM_DEFAULT_DISC_INTERVAL;
    }

    BTM_TRACE_API("BTM_SetDiscoverability: mode %d [NonDisc-0, Lim-1, Gen-2], window 0x%04x, interval 0x%04x",
                  inq_mode, window, interval);

    /*** Check for valid window and interval parameters ***/
    /*** Only check window and duration if mode is connectable ***/
    if(inq_mode != BTM_NON_DISCOVERABLE)
    {
        /* window must be less than or equal to interval */
        if(window < HCI_MIN_INQUIRYSCAN_WINDOW     ||
                window > HCI_MAX_INQUIRYSCAN_WINDOW     ||
                interval < HCI_MIN_INQUIRYSCAN_INTERVAL ||
                interval > HCI_MAX_INQUIRYSCAN_INTERVAL ||
                window > interval)
        {
            return (BTM_ILLEGAL_VALUE);
        }
    }

    /* Set the IAC if needed */
    if(inq_mode != BTM_NON_DISCOVERABLE)
    {
        if(inq_mode & BTM_LIMITED_DISCOVERABLE)
        {
            /* Use the GIAC and LIAC codes for limited discoverable mode */
            wm_memcpy(temp_lap[0], limited_inq_lap, LAP_LEN);
            wm_memcpy(temp_lap[1], general_inq_lap, LAP_LEN);

            if(!btsnd_hcic_write_cur_iac_lap(2, (LAP * const) temp_lap))
            {
                return (BTM_NO_RESOURCES);      /* Cannot continue */
            }
        }
        else
        {
            if(!btsnd_hcic_write_cur_iac_lap(1, (LAP * const) &general_inq_lap))
            {
                return (BTM_NO_RESOURCES);      /* Cannot continue */
            }
        }

        scan_mode |= HCI_INQUIRY_SCAN_ENABLED;
    }

    /* Send down the inquiry scan window and period if changed */
    if((window != btm_cb.btm_inq_vars.inq_scan_window) ||
            (interval != btm_cb.btm_inq_vars.inq_scan_period))
    {
        if(btsnd_hcic_write_inqscan_cfg(interval, window))
        {
            btm_cb.btm_inq_vars.inq_scan_window = window;
            btm_cb.btm_inq_vars.inq_scan_period = interval;
        }
        else
        {
            return (BTM_NO_RESOURCES);
        }
    }

    if(btm_cb.btm_inq_vars.connectable_mode & BTM_CONNECTABLE_MASK)
    {
        scan_mode |= HCI_PAGE_SCAN_ENABLED;
    }

    if(btsnd_hcic_write_scan_enable(scan_mode))
    {
        btm_cb.btm_inq_vars.discoverable_mode &= (~BTM_DISCOVERABLE_MASK);
        btm_cb.btm_inq_vars.discoverable_mode |= inq_mode;
    }
    else
    {
        return (BTM_NO_RESOURCES);
    }

    /* Change the service class bit if mode has changed */
    p_cod = BTM_ReadDeviceClass();
    BTM_COD_SERVICE_CLASS(service_class, p_cod);
    is_limited = (inq_mode & BTM_LIMITED_DISCOVERABLE) ? TRUE : FALSE;
    cod_limited = (service_class & BTM_COD_SERVICE_LMTD_DISCOVER) ? TRUE : FALSE;

    if(is_limited ^ cod_limited)
    {
        BTM_COD_MINOR_CLASS(minor, p_cod);
        BTM_COD_MAJOR_CLASS(major, p_cod);

        if(is_limited)
        {
            service_class |= BTM_COD_SERVICE_LMTD_DISCOVER;
        }
        else
        {
            service_class &= ~BTM_COD_SERVICE_LMTD_DISCOVER;
        }

        FIELDS_TO_COD(cod, minor, major, service_class);
        (void) BTM_SetDeviceClass(cod);
    }

    return (BTM_SUCCESS);
}

/*******************************************************************************
**
** Function         BTM_SetInquiryScanType
**
** Description      This function is called to set the iquiry scan-type to
**                  standard or interlaced.
**
** Returns          BTM_SUCCESS if successful
**                  BTM_MODE_UNSUPPORTED if not a 1.2 device
**                  BTM_WRONG_MODE if the device is not up.
**
*******************************************************************************/
tBTM_STATUS BTM_SetInquiryScanType(uint16_t scan_type)
{
    BTM_TRACE_API("BTM_SetInquiryScanType");

    if(scan_type != BTM_SCAN_TYPE_STANDARD && scan_type != BTM_SCAN_TYPE_INTERLACED)
    {
        return (BTM_ILLEGAL_VALUE);
    }

    /* whatever app wants if device is not 1.2 scan type should be STANDARD */
    if(!HCI_LMP_INTERLACED_INQ_SCAN_SUPPORTED(btm_cb.devcb.local_lmp_features[HCI_EXT_FEATURES_PAGE_0]))
    {
        return (BTM_MODE_UNSUPPORTED);
    }

    /* Check for scan type if configuration has been changed */
    if(scan_type != btm_cb.btm_inq_vars.inq_scan_type)
    {
        if(BTM_IsDeviceUp())
        {
            if(btsnd_hcic_write_inqscan_type((uint8_t)scan_type))
            {
                btm_cb.btm_inq_vars.inq_scan_type = scan_type;
            }
            else
            {
                return (BTM_NO_RESOURCES);
            }
        }
        else
        {
            return (BTM_WRONG_MODE);
        }
    }

    return (BTM_SUCCESS);
}

/*******************************************************************************
**
** Function         BTM_SetPageScanType
**
** Description      This function is called to set the page scan-type to
**                  standard or interlaced.
**
** Returns          BTM_SUCCESS if successful
**                  BTM_MODE_UNSUPPORTED if not a 1.2 device
**                  BTM_WRONG_MODE if the device is not up.
**
*******************************************************************************/
tBTM_STATUS BTM_SetPageScanType(uint16_t scan_type)
{
    BTM_TRACE_API("BTM_SetPageScanType");

    if(scan_type != BTM_SCAN_TYPE_STANDARD && scan_type != BTM_SCAN_TYPE_INTERLACED)
    {
        return (BTM_ILLEGAL_VALUE);
    }

    /* whatever app wants if device is not 1.2 scan type should be STANDARD */
    if(!HCI_LMP_INTERLACED_PAGE_SCAN_SUPPORTED(btm_cb.devcb.local_lmp_features[HCI_EXT_FEATURES_PAGE_0]))
    {
        return (BTM_MODE_UNSUPPORTED);
    }

    /* Check for scan type if configuration has been changed */
    if(scan_type != btm_cb.btm_inq_vars.page_scan_type)
    {
        if(BTM_IsDeviceUp())
        {
            if(btsnd_hcic_write_pagescan_type((uint8_t)scan_type))
            {
                btm_cb.btm_inq_vars.page_scan_type  = scan_type;
            }
            else
            {
                return (BTM_NO_RESOURCES);
            }
        }
        else
        {
            return (BTM_WRONG_MODE);
        }
    }

    return (BTM_SUCCESS);
}


/*******************************************************************************
**
** Function         BTM_SetInquiryMode
**
** Description      This function is called to set standard or with RSSI
**                  mode of the inquiry for local device.
**
** Output Params:   mode - standard, with RSSI, extended
**
** Returns          BTM_SUCCESS if successful
**                  BTM_NO_RESOURCES if couldn't get a memory pool buffer
**                  BTM_ILLEGAL_VALUE if a bad parameter was detected
**                  BTM_WRONG_MODE if the device is not up.
**
*******************************************************************************/
tBTM_STATUS BTM_SetInquiryMode(uint8_t mode)
{
    BTM_TRACE_API("BTM_SetInquiryMode");

    if(mode == BTM_INQ_RESULT_STANDARD)
    {
        /* mandatory mode */
    }
    else
        if(mode == BTM_INQ_RESULT_WITH_RSSI)
        {
            if(!HCI_LMP_INQ_RSSI_SUPPORTED(btm_cb.devcb.local_lmp_features[HCI_EXT_FEATURES_PAGE_0]))
            {
                return (BTM_MODE_UNSUPPORTED);
            }
        }
        else
            if(mode == BTM_INQ_RESULT_EXTENDED)
            {
                if(!HCI_EXT_INQ_RSP_SUPPORTED(btm_cb.devcb.local_lmp_features[HCI_EXT_FEATURES_PAGE_0]))
                {
                    return (BTM_MODE_UNSUPPORTED);
                }
            }
            else
            {
                return (BTM_ILLEGAL_VALUE);
            }

    if(!BTM_IsDeviceUp())
    {
        return (BTM_WRONG_MODE);
    }

    if(!btsnd_hcic_write_inquiry_mode(mode))
    {
        return (BTM_NO_RESOURCES);
    }

    return (BTM_SUCCESS);
}

/*******************************************************************************
**
** Function         BTM_ReadDiscoverability
**
** Description      This function is called to read the current discoverability
**                  mode of the device.
**
** Output Params:   p_window - current inquiry scan duration
**                  p_interval - current inquiry scan interval
**
** Returns          BTM_NON_DISCOVERABLE, BTM_LIMITED_DISCOVERABLE, or
**                  BTM_GENERAL_DISCOVERABLE
**
*******************************************************************************/
uint16_t BTM_ReadDiscoverability(uint16_t *p_window, uint16_t *p_interval)
{
    BTM_TRACE_API("BTM_ReadDiscoverability");

    if(p_window)
    {
        *p_window = btm_cb.btm_inq_vars.inq_scan_window;
    }

    if(p_interval)
    {
        *p_interval = btm_cb.btm_inq_vars.inq_scan_period;
    }

    return (btm_cb.btm_inq_vars.discoverable_mode);
}


/*******************************************************************************
**
** Function         BTM_SetPeriodicInquiryMode
**
** Description      This function is called to set the device periodic inquiry mode.
**                  If the duration is zero, the periodic inquiry mode is cancelled.
**
**                  Note: We currently do not allow concurrent inquiry and periodic inquiry.
**
** Parameters:      p_inqparms - pointer to the inquiry information
**                      mode - GENERAL or LIMITED inquiry
**                      duration - length in 1.28 sec intervals (If '0', the inquiry is CANCELLED)
**                      max_resps - maximum amount of devices to search for before ending the inquiry
**                      filter_cond_type - BTM_CLR_INQUIRY_FILTER, BTM_FILTER_COND_DEVICE_CLASS, or
**                                         BTM_FILTER_COND_BD_ADDR
**                      filter_cond - value for the filter (based on filter_cond_type)
**
**                  max_delay - maximum amount of time between successive inquiries
**                  min_delay - minimum amount of time between successive inquiries
**                  p_results_cb - callback returning pointer to results (tBTM_INQ_RESULTS)
**
** Returns          BTM_CMD_STARTED if successfully started
**                  BTM_ILLEGAL_VALUE if a bad parameter is detected
**                  BTM_NO_RESOURCES if could not allocate a message buffer
**                  BTM_SUCCESS - if cancelling the periodic inquiry
**                  BTM_BUSY - if an inquiry is already active
**                  BTM_WRONG_MODE if the device is not up.
**
*******************************************************************************/
tBTM_STATUS BTM_SetPeriodicInquiryMode(tBTM_INQ_PARMS *p_inqparms, uint16_t max_delay,
                                       uint16_t min_delay, tBTM_INQ_RESULTS_CB *p_results_cb)
{
    tBTM_STATUS  status;
    tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
    BTM_TRACE_API("BTM_SetPeriodicInquiryMode: mode: %d, dur: %d, rsps: %d, flt: %d, min: %d, max: %d",
                  p_inqparms->mode, p_inqparms->duration, p_inqparms->max_resps,
                  p_inqparms->filter_cond_type, min_delay, max_delay);

    /*** Make sure the device is ready ***/
    if(!BTM_IsDeviceUp())
    {
        return (BTM_WRONG_MODE);
    }

    /* Only one active inquiry is allowed in this implementation.
       Also do not allow an inquiry if the inquiry filter is being updated */
    if(p_inq->inq_active || p_inq->inqfilt_active)
    {
        return (BTM_BUSY);
    }

    /* If illegal parameters return FALSE */
    if(p_inqparms->mode != BTM_GENERAL_INQUIRY &&
            p_inqparms->mode != BTM_LIMITED_INQUIRY)
    {
        return (BTM_ILLEGAL_VALUE);
    }

    /* Verify the parameters for this command */
    if(p_inqparms->duration < BTM_MIN_INQUIRY_LEN     ||
            p_inqparms->duration > BTM_MAX_INQUIRY_LENGTH  ||
            min_delay <= p_inqparms->duration              ||
            min_delay < BTM_PER_INQ_MIN_MIN_PERIOD         ||
            min_delay > BTM_PER_INQ_MAX_MIN_PERIOD         ||
            max_delay <= min_delay                         ||
            max_delay < BTM_PER_INQ_MIN_MAX_PERIOD)
        /*       max_delay > BTM_PER_INQ_MAX_MAX_PERIOD)*/
        /*  BTM_PER_INQ_MAX_MAX_PERIOD set to 1's in all bits. Condition resulting in false always*/
    {
        return (BTM_ILLEGAL_VALUE);
    }

    /* Save the inquiry parameters to be used upon the completion of setting/clearing the inquiry filter */
    p_inq->inqparms = *p_inqparms;
    p_inq->per_min_delay = min_delay;
    p_inq->per_max_delay = max_delay;
    p_inq->inq_cmpl_info.num_resp = 0;         /* Clear the results counter */
    p_inq->p_inq_results_cb = p_results_cb;
    p_inq->inq_active = (uint8_t)((p_inqparms->mode == BTM_LIMITED_INQUIRY) ?
                                  (BTM_LIMITED_INQUIRY_ACTIVE | BTM_PERIODIC_INQUIRY_ACTIVE) :
                                  (BTM_GENERAL_INQUIRY_ACTIVE | BTM_PERIODIC_INQUIRY_ACTIVE));

    /* If a filter is specified, then save it for later and clear the current filter.
       The setting of the filter is done upon completion of clearing of the previous
       filter.
    */
    if(p_inqparms->filter_cond_type != BTM_CLR_INQUIRY_FILTER)
    {
        p_inq->state = BTM_INQ_CLR_FILT_STATE;
        p_inqparms->filter_cond_type = BTM_CLR_INQUIRY_FILTER;
    }
    else    /* The filter is not being used so simply clear it; the inquiry can start after this operation */
    {
        p_inq->state = BTM_INQ_SET_FILT_STATE;
    }

    /* Before beginning the inquiry the current filter must be cleared, so initiate the command */
    if((status = btm_set_inq_event_filter(p_inqparms->filter_cond_type, &p_inqparms->filter_cond)) != BTM_CMD_STARTED)
    {
        /* If set filter command is not succesful reset the state */
        p_inq->p_inq_results_cb = NULL;
        p_inq->state = BTM_INQ_INACTIVE_STATE;
    }

    return (status);
}


/*******************************************************************************
**
** Function         BTM_CancelPeriodicInquiry
**
** Description      This function cancels a periodic inquiry
**
** Returns
**                  BTM_NO_RESOURCES if could not allocate a message buffer
**                  BTM_SUCCESS - if cancelling the periodic inquiry
**                  BTM_WRONG_MODE if the device is not up.
**
*******************************************************************************/
tBTM_STATUS BTM_CancelPeriodicInquiry(void)
{
    tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
    tBTM_STATUS          status = BTM_SUCCESS;
    BTM_TRACE_API("BTM_CancelPeriodicInquiry called");

    /*** Make sure the device is ready ***/
    if(!BTM_IsDeviceUp())
    {
        return (BTM_WRONG_MODE);
    }

    /* Only cancel if one is active */
    if(btm_cb.btm_inq_vars.inq_active & BTM_PERIODIC_INQUIRY_ACTIVE)
    {
        btm_cb.btm_inq_vars.inq_active = BTM_INQUIRY_INACTIVE;
        btm_cb.btm_inq_vars.p_inq_results_cb = (tBTM_INQ_RESULTS_CB *) NULL;

        if(!btsnd_hcic_exit_per_inq())
        {
            status = BTM_NO_RESOURCES;
        }

        /* If the event filter is in progress, mark it so that the processing of the return
           event will be ignored */
        if(p_inq->inqfilt_active)
        {
            p_inq->pending_filt_complete_event++;
        }

        p_inq->inqfilt_active = FALSE;
        p_inq->inq_counter++;
    }

    return (status);
}


/*******************************************************************************
**
** Function         BTM_SetConnectability
**
** Description      This function is called to set the device into or out of
**                  connectable mode. Discoverable mode means page scans enabled.
**
** Returns          BTM_SUCCESS if successful
**                  BTM_ILLEGAL_VALUE if a bad parameter is detected
**                  BTM_NO_RESOURCES if could not allocate a message buffer
**                  BTM_WRONG_MODE if the device is not up.
**
*******************************************************************************/
tBTM_STATUS BTM_SetConnectability(uint16_t page_mode, uint16_t window, uint16_t interval)
{
    uint8_t    scan_mode = 0;
    tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
    BTM_TRACE_API("BTM_SetConnectability,page_mode=%d, state=%d\r\n", page_mode, btm_cb.devcb.state);
    #if (BLE_INCLUDED == TRUE && BLE_INCLUDED == TRUE)

    if(HCI_LE_HOST_SUPPORTED(btm_cb.devcb.local_lmp_features[HCI_EXT_FEATURES_PAGE_1]))
    {
        if(btm_ble_set_connectability(page_mode) != BTM_SUCCESS)
        {
            return BTM_NO_RESOURCES;
        }

        p_inq->connectable_mode &= (~BTM_BLE_CONNECTABLE_MASK);
        p_inq->connectable_mode |= (page_mode & BTM_BLE_CONNECTABLE_MASK);
    }

    page_mode &= ~BTM_BLE_CONNECTABLE_MASK;
    #endif

    /*** Check mode parameter ***/
    if(page_mode != BTM_NON_CONNECTABLE && page_mode != BTM_CONNECTABLE)
    {
        return (BTM_ILLEGAL_VALUE);
    }

    /* Make sure the controller is active */
    if(btm_cb.devcb.state < BTM_DEV_STATE_READY)
    {
        return (BTM_DEV_RESET);
    }

    /* If the window and/or interval is '0', set to default values */
    if(!window)
    {
        window = BTM_DEFAULT_CONN_WINDOW;
    }

    if(!interval)
    {
        interval = BTM_DEFAULT_CONN_INTERVAL;
    }

    BTM_TRACE_API("BTM_SetConnectability: mode %d [NonConn-0, Conn-1], window 0x%04x, interval 0x%04x\r\n",
                  page_mode, window, interval);

    /*** Check for valid window and interval parameters ***/
    /*** Only check window and duration if mode is connectable ***/
    if(page_mode == BTM_CONNECTABLE)
    {
        /* window must be less than or equal to interval */
        if(window < HCI_MIN_PAGESCAN_WINDOW     ||
                window > HCI_MAX_PAGESCAN_WINDOW     ||
                interval < HCI_MIN_PAGESCAN_INTERVAL ||
                interval > HCI_MAX_PAGESCAN_INTERVAL ||
                window > interval)
        {
            return (BTM_ILLEGAL_VALUE);
        }

        scan_mode |= HCI_PAGE_SCAN_ENABLED;
    }

    if((window != p_inq->page_scan_window) ||
            (interval != p_inq->page_scan_period))
    {
        p_inq->page_scan_window = window;
        p_inq->page_scan_period = interval;

        if(!btsnd_hcic_write_pagescan_cfg(interval, window))
        {
            return (BTM_NO_RESOURCES);
        }
    }

    /* Keep the inquiry scan as previouosly set */
    if(p_inq->discoverable_mode & BTM_DISCOVERABLE_MASK)
    {
        scan_mode |= HCI_INQUIRY_SCAN_ENABLED;
    }

    if(btsnd_hcic_write_scan_enable(scan_mode))
    {
        p_inq->connectable_mode &= (~BTM_CONNECTABLE_MASK);
        p_inq->connectable_mode |= page_mode;
        return (BTM_SUCCESS);
    }

    return (BTM_NO_RESOURCES);
}


/*******************************************************************************
**
** Function         BTM_ReadConnectability
**
** Description      This function is called to read the current discoverability
**                  mode of the device.
** Output Params    p_window - current page scan duration
**                  p_interval - current time between page scans
**
** Returns          BTM_NON_CONNECTABLE or BTM_CONNECTABLE
**
*******************************************************************************/
uint16_t BTM_ReadConnectability(uint16_t *p_window, uint16_t *p_interval)
{
    BTM_TRACE_API("BTM_ReadConnectability");

    if(p_window)
    {
        *p_window = btm_cb.btm_inq_vars.page_scan_window;
    }

    if(p_interval)
    {
        *p_interval = btm_cb.btm_inq_vars.page_scan_period;
    }

    return (btm_cb.btm_inq_vars.connectable_mode);
}



/*******************************************************************************
**
** Function         BTM_IsInquiryActive
**
** Description      This function returns a bit mask of the current inquiry state
**
** Returns          BTM_INQUIRY_INACTIVE if inactive (0)
**                  BTM_LIMITED_INQUIRY_ACTIVE if a limted inquiry is active
**                  BTM_GENERAL_INQUIRY_ACTIVE if a general inquiry is active
**                  BTM_PERIODIC_INQUIRY_ACTIVE if a periodic inquiry is active
**
*******************************************************************************/
uint16_t BTM_IsInquiryActive(void)
{
    BTM_TRACE_API("BTM_IsInquiryActive");
    return(btm_cb.btm_inq_vars.inq_active);
}



/*******************************************************************************
**
** Function         BTM_CancelInquiry
**
** Description      This function cancels an inquiry if active
**
** Returns          BTM_SUCCESS if successful
**                  BTM_NO_RESOURCES if could not allocate a message buffer
**                  BTM_WRONG_MODE if the device is not up.
**
*******************************************************************************/
tBTM_STATUS BTM_CancelInquiry(void)
{
    tBTM_STATUS           status = BTM_SUCCESS;
    tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
    #if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE)
    uint8_t active_mode = p_inq->inq_active;
    #endif
    BTM_TRACE_API("BTM_CancelInquiry called");

    /*** Make sure the device is ready ***/
    if(!BTM_IsDeviceUp())
    {
        return (BTM_WRONG_MODE);
    }

    /* Only cancel if not in periodic mode, otherwise the caller should call BTM_CancelPeriodicMode */
    if((p_inq->inq_active & BTM_INQUIRY_ACTIVE_MASK) != 0 &&
            (!(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE)))
    {
        p_inq->inq_active = BTM_INQUIRY_INACTIVE;
        p_inq->state = BTM_INQ_INACTIVE_STATE;
        p_inq->p_inq_results_cb = (tBTM_INQ_RESULTS_CB *) NULL;   /* Do not notify caller anymore */
        p_inq->p_inq_cmpl_cb = (tBTM_CMPL_CB *) NULL;    /* Do not notify caller anymore */

        /* If the event filter is in progress, mark it so that the processing of the return
            event will be ignored */
        if(p_inq->inqfilt_active)
        {
            p_inq->inqfilt_active = FALSE;
            p_inq->pending_filt_complete_event++;
        }
        /* Initiate the cancel inquiry */
        else
        {
            if(((p_inq->inqparms.mode & BTM_BR_INQUIRY_MASK) != 0)
                #if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE)
                    && (active_mode & BTM_BR_INQUIRY_MASK)
                #endif
              )
            {
                if(!btsnd_hcic_inq_cancel())
                {
                    status = BTM_NO_RESOURCES;
                }
            }

            #if BLE_INCLUDED == TRUE

            if(((p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) != 0)
                #if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE)
                    && (active_mode & BTM_BLE_INQ_ACTIVE_MASK)
                #endif
              )
            {
                btm_ble_stop_inquiry();
            }

            #endif
        }

        /* Do not send the BUSY_LEVEL event yet. Wait for the cancel_complete event
         * and then send the BUSY_LEVEL event
         * btm_acl_update_busy_level (BTM_BLI_INQ_DONE_EVT);
         */
        p_inq->inq_counter++;
        btm_clr_inq_result_flt();
    }

    return (status);
}


/*******************************************************************************
**
** Function         BTM_StartInquiry
**
** Description      This function is called to start an inquiry.
**
** Parameters:      p_inqparms - pointer to the inquiry information
**                      mode - GENERAL or LIMITED inquiry, BR/LE bit mask seperately
**                      duration - length in 1.28 sec intervals (If '0', the inquiry is CANCELLED)
**                      max_resps - maximum amount of devices to search for before ending the inquiry
**                      filter_cond_type - BTM_CLR_INQUIRY_FILTER, BTM_FILTER_COND_DEVICE_CLASS, or
**                                         BTM_FILTER_COND_BD_ADDR
**                      filter_cond - value for the filter (based on filter_cond_type)
**
**                  p_results_cb   - Pointer to the callback routine which gets called
**                                upon receipt of an inquiry result. If this field is
**                                NULL, the application is not notified.
**
**                  p_cmpl_cb   - Pointer to the callback routine which gets called
**                                upon completion.  If this field is NULL, the
**                                application is not notified when completed.
** Returns          tBTM_STATUS
**                  BTM_CMD_STARTED if successfully initiated
**                  BTM_BUSY if already in progress
**                  BTM_ILLEGAL_VALUE if parameter(s) are out of range
**                  BTM_NO_RESOURCES if could not allocate resources to start the command
**                  BTM_WRONG_MODE if the device is not up.
**
*******************************************************************************/
tBTM_STATUS BTM_StartInquiry(tBTM_INQ_PARMS *p_inqparms, tBTM_INQ_RESULTS_CB *p_results_cb,
                             tBTM_CMPL_CB *p_cmpl_cb)
{
    tBTM_STATUS  status = BTM_CMD_STARTED;
    tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
    BTM_TRACE_API("BTM_StartInquiry: mode: %d, dur: %d, rsps: %d, flt: %d",
                  p_inqparms->mode, p_inqparms->duration, p_inqparms->max_resps,
                  p_inqparms->filter_cond_type);

    /* Only one active inquiry is allowed in this implementation.
       Also do not allow an inquiry if the inquiry filter is being updated */
    if(p_inq->inq_active || p_inq->inqfilt_active)
    {
        #if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE)

        /*check if LE observe is already running*/
        if(p_inq->scan_type == INQ_LE_OBSERVE && p_inq->p_inq_ble_results_cb != NULL)
        {
            BTM_TRACE_API("BTM_StartInquiry: LE observe in progress");
            p_inq->scan_type = INQ_GENERAL;
            p_inq->inq_active = BTM_INQUIRY_INACTIVE;
            btm_cb.ble_ctr_cb.inq_var.scan_type = BTM_BLE_SCAN_MODE_NONE;
            btsnd_hcic_ble_set_scan_enable(BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE);
        }
        else
        #endif
        {
            return (BTM_BUSY);
            BTM_TRACE_API("BTM_StartInquiry: return BUSY");
        }
    }
    else
    {
        p_inq->scan_type = INQ_GENERAL;
    }

    /*** Make sure the device is ready ***/
    if(!BTM_IsDeviceUp())
    {
        return (BTM_WRONG_MODE);
    }

    if((p_inqparms->mode & BTM_BR_INQUIRY_MASK) != BTM_GENERAL_INQUIRY &&
            (p_inqparms->mode & BTM_BR_INQUIRY_MASK) != BTM_LIMITED_INQUIRY
        #if (BLE_INCLUDED == TRUE)
            && (p_inqparms->mode & BTM_BLE_INQUIRY_MASK) != BTM_BLE_GENERAL_INQUIRY
            && (p_inqparms->mode & BTM_BLE_INQUIRY_MASK) != BTM_BLE_LIMITED_INQUIRY
        #endif
      )
    {
        return (BTM_ILLEGAL_VALUE);
    }

    #if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE)

    if(p_inq->next_state == BTM_FINISH)
    {
        return BTM_ILLEGAL_VALUE;
    }

    #endif
    /* Save the inquiry parameters to be used upon the completion of setting/clearing the inquiry filter */
    p_inq->inqparms = *p_inqparms;
    /* Initialize the inquiry variables */
    p_inq->state = BTM_INQ_ACTIVE_STATE;
    p_inq->p_inq_cmpl_cb = p_cmpl_cb;
    p_inq->p_inq_results_cb = p_results_cb;
    p_inq->inq_cmpl_info.num_resp = 0;         /* Clear the results counter */
    p_inq->inq_active = p_inqparms->mode;
    BTM_TRACE_DEBUG("BTM_StartInquiry: p_inq->inq_active = 0x%02x", p_inq->inq_active);
    /* interleave scan minimal conditions */
    #if (BLE_INCLUDED==TRUE && (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE))

    /* check if both modes are present */
    if((p_inqparms->mode & BTM_BLE_INQUIRY_MASK) && (p_inqparms->mode & BTM_BR_INQUIRY_MASK))
    {
        BTM_TRACE_API("BTM:Interleave Inquiry Mode Set");
        p_inqparms->duration = p_inqparms->intl_duration[p_inq->next_state];
        p_inq->inqparms.duration = p_inqparms->duration;
    }
    else
    {
        BTM_TRACE_API("BTM:Single Mode: No interleaving, Mode:0x%02x", p_inqparms->mode);
        p_inq->next_state = BTM_NO_INTERLEAVING;
    }

    #endif
    /* start LE inquiry here if requested */
    #if BLE_INCLUDED == TRUE

    if((p_inqparms->mode & BTM_BLE_INQUIRY_MASK)
        #if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE)
            && (p_inq->next_state == BTM_BLE_ONE || p_inq->next_state == BTM_BLE_TWO ||
                p_inq->next_state == BTM_NO_INTERLEAVING)
        #endif
      )
    {
        #if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE)
        p_inq->inq_active = (p_inqparms->mode & BTM_BLE_INQUIRY_MASK);
        BTM_TRACE_API("BTM:Starting LE Scan with duration %d and activeMode:0x%02x",
                      p_inqparms->duration, (p_inqparms->mode & BTM_BLE_INQUIRY_MASK));
        #endif

        if(!HCI_LE_HOST_SUPPORTED(btm_cb.devcb.local_lmp_features[HCI_EXT_FEATURES_PAGE_1]))
        {
            p_inq->inqparms.mode &= ~ BTM_BLE_INQUIRY_MASK;
            status = BTM_ILLEGAL_VALUE;
        }
        /* BLE for now does not support filter condition for inquiry */
        else
            if((status = btm_ble_start_inquiry((uint8_t)(p_inqparms->mode & BTM_BLE_INQUIRY_MASK),
                                               p_inqparms->duration)) != BTM_CMD_STARTED)
            {
                BTM_TRACE_ERROR("Err Starting LE Inquiry.");
                p_inq->inqparms.mode &= ~ BTM_BLE_INQUIRY_MASK;
            }

        #if (!defined(BTA_HOST_INTERLEAVE_SEARCH) || BTA_HOST_INTERLEAVE_SEARCH == FALSE)
        p_inqparms->mode &= ~BTM_BLE_INQUIRY_MASK;
        #endif
        #if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE)

        if(p_inq->next_state == BTM_NO_INTERLEAVING)
        {
            p_inq->next_state = BTM_FINISH;
        }
        else
        {
            BTM_TRACE_API("BTM:Interleaving: started LE scan, Advancing to next state: %d",
                          p_inq->next_state + 1);
            p_inq->next_state += 1;
        }

        /* reset next_state if status <> BTM_Started */
        if(status != BTM_CMD_STARTED)
        {
            p_inq->next_state = BTM_BR_ONE;
        }

        /* if interleave scan..return here */
        return status;
        #endif
        BTM_TRACE_DEBUG("BTM_StartInquiry: mode = %02x", p_inqparms->mode);
    }

    #endif /* end of BLE_INCLUDED */

    /* we're done with this routine if BR/EDR inquiry is not desired. */
    if((p_inqparms->mode & BTM_BR_INQUIRY_MASK) == BTM_INQUIRY_NONE)
    {
        return status;
    }

    /* BR/EDR inquiry portion */
    #if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE)

    if((p_inq->next_state == BTM_BR_ONE || p_inq->next_state == BTM_BR_TWO ||
            p_inq->next_state == BTM_NO_INTERLEAVING))
    {
        p_inq->inq_active = (p_inqparms->mode & BTM_BR_INQUIRY_MASK);
    #endif

        /* If a filter is specified, then save it for later and clear the current filter.
           The setting of the filter is done upon completion of clearing of the previous
           filter.
        */
        switch(p_inqparms->filter_cond_type)
        {
            case BTM_CLR_INQUIRY_FILTER:
                p_inq->state = BTM_INQ_SET_FILT_STATE;
                break;

            case BTM_FILTER_COND_DEVICE_CLASS:
            case BTM_FILTER_COND_BD_ADDR:
                /* The filter is not being used so simply clear it;
                    the inquiry can start after this operation */
                p_inq->state = BTM_INQ_CLR_FILT_STATE;
                p_inqparms->filter_cond_type = BTM_CLR_INQUIRY_FILTER;
                /* =============>>>> adding LE filtering here ????? */
                break;

            default:
                return (BTM_ILLEGAL_VALUE);
        }

        /* Before beginning the inquiry the current filter must be cleared, so initiate the command */
        if((status = btm_set_inq_event_filter(p_inqparms->filter_cond_type,
                                              &p_inqparms->filter_cond)) != BTM_CMD_STARTED)
        {
            p_inq->state = BTM_INQ_INACTIVE_STATE;
        }

        #if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE)

        if(p_inq->next_state == BTM_NO_INTERLEAVING)
        {
            p_inq->next_state = BTM_FINISH;
        }
        else
        {
            BTM_TRACE_API("BTM:Interleaving: Started BTM inq, Advancing to next state: %d",
                          p_inq->next_state + 1);
            p_inq->next_state += 1;
        }
    }

    if(status != BTM_CMD_STARTED)
    {
        /* Some error beginning the scan process.
           Reset the next_state parameter.. Do we need to reset the inq_active also?
        */
        BTM_TRACE_API("BTM:Interleaving: Error in Starting inquiry, status: 0x%02x", status);
        p_inq->next_state = BTM_BR_ONE;
    }

        #endif
    return (status);
}


/*******************************************************************************
**
** Function         BTM_ReadRemoteDeviceName
**
** Description      This function initiates a remote device HCI command to the
**                  controller and calls the callback when the process has completed.
**
** Input Params:    remote_bda      - device address of name to retrieve
**                  p_cb            - callback function called when BTM_CMD_STARTED
**                                    is returned.
**                                    A pointer to tBTM_REMOTE_DEV_NAME is passed to the
**                                    callback.
**
** Returns
**                  BTM_CMD_STARTED is returned if the request was successfully sent
**                                  to HCI.
**                  BTM_BUSY if already in progress
**                  BTM_UNKNOWN_ADDR if device address is bad
**                  BTM_NO_RESOURCES if could not allocate resources to start the command
**                  BTM_WRONG_MODE if the device is not up.
**
*******************************************************************************/
tBTM_STATUS  BTM_ReadRemoteDeviceName(BD_ADDR remote_bda, tBTM_CMPL_CB *p_cb
                                      , tBT_TRANSPORT transport)
{
    tBTM_INQ_INFO   *p_cur = NULL;
    tINQ_DB_ENT     *p_i;
    BTM_TRACE_API("BTM_ReadRemoteDeviceName: bd addr [%02x%02x%02x%02x%02x%02x]",
                  remote_bda[0], remote_bda[1], remote_bda[2],
                  remote_bda[3], remote_bda[4], remote_bda[5]);

    /* Use the remote device's clock offset if it is in the local inquiry database */
    if((p_i = btm_inq_db_find(remote_bda)) != NULL)
    {
        p_cur = &p_i->inq_info;
    }

    BTM_TRACE_API("no device found in inquiry db");
    #if (BLE_INCLUDED == TRUE)

    if(transport == BT_TRANSPORT_LE)
    {
        return btm_ble_read_remote_name(remote_bda, p_cur, p_cb);
    }
    else
    #endif
        return (btm_initiate_rem_name(remote_bda, p_cur, BTM_RMT_NAME_EXT,
                                      BTM_EXT_RMT_NAME_TIMEOUT_MS, p_cb));
}

/*******************************************************************************
**
** Function         BTM_CancelRemoteDeviceName
**
** Description      This function initiates the cancel request for the specified
**                  remote device.
**
** Input Params:    None
**
** Returns
**                  BTM_CMD_STARTED is returned if the request was successfully sent
**                                  to HCI.
**                  BTM_NO_RESOURCES if could not allocate resources to start the command
**                  BTM_WRONG_MODE if there is not an active remote name request.
**
*******************************************************************************/
tBTM_STATUS  BTM_CancelRemoteDeviceName(void)
{
    tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
    BTM_TRACE_API("BTM_CancelRemoteDeviceName()");

    /* Make sure there is not already one in progress */
    if(p_inq->remname_active)
    {
        #if BLE_INCLUDED == TRUE

        if(BTM_UseLeLink(p_inq->remname_bda))
        {
            if(btm_ble_cancel_remote_name(p_inq->remname_bda))
            {
                return (BTM_CMD_STARTED);
            }
            else
            {
                return (BTM_UNKNOWN_ADDR);
            }
        }
        else
        #endif
            if(btsnd_hcic_rmt_name_req_cancel(p_inq->remname_bda))
            {
                return (BTM_CMD_STARTED);
            }
            else
            {
                return (BTM_NO_RESOURCES);
            }
    }
    else
    {
        return (BTM_WRONG_MODE);
    }
}

/*******************************************************************************
**
** Function         BTM_InqDbRead
**
** Description      This function looks through the inquiry database for a match
**                  based on Bluetooth Device Address. This is the application's
**                  interface to get the inquiry details of a specific BD address.
**
** Returns          pointer to entry, or NULL if not found
**
*******************************************************************************/
tBTM_INQ_INFO *BTM_InqDbRead(BD_ADDR p_bda)
{
    BTM_TRACE_API("BTM_InqDbRead: bd addr [%02x%02x%02x%02x%02x%02x]",
                  p_bda[0], p_bda[1], p_bda[2], p_bda[3], p_bda[4], p_bda[5]);
    tINQ_DB_ENT *p_ent = btm_inq_db_find(p_bda);

    if(!p_ent)
    {
        return NULL;
    }

    return &p_ent->inq_info;
}


/*******************************************************************************
**
** Function         BTM_InqDbFirst
**
** Description      This function looks through the inquiry database for the first
**                  used entry, and returns that. This is used in conjunction with
**                  BTM_InqDbNext by applications as a way to walk through the
**                  inquiry database.
**
** Returns          pointer to first in-use entry, or NULL if DB is empty
**
*******************************************************************************/
tBTM_INQ_INFO *BTM_InqDbFirst(void)
{
    uint16_t       xx;
    tINQ_DB_ENT  *p_ent = btm_cb.btm_inq_vars.inq_db;

    for(xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++)
    {
        if(p_ent->in_use)
        {
            return (&p_ent->inq_info);
        }
    }

    /* If here, no used entry found */
    return ((tBTM_INQ_INFO *)NULL);
}


/*******************************************************************************
**
** Function         BTM_InqDbNext
**
** Description      This function looks through the inquiry database for the next
**                  used entry, and returns that.  If the input parameter is NULL,
**                  the first entry is returned.
**
** Returns          pointer to next in-use entry, or NULL if no more found.
**
*******************************************************************************/
tBTM_INQ_INFO *BTM_InqDbNext(tBTM_INQ_INFO *p_cur)
{
    tINQ_DB_ENT  *p_ent;
    uint16_t        inx;

    if(p_cur)
    {
        p_ent = (tINQ_DB_ENT *)((uint8_t *)p_cur - offsetof(tINQ_DB_ENT, inq_info));
        inx = (uint16_t)((p_ent - btm_cb.btm_inq_vars.inq_db) + 1);

        for(p_ent = &btm_cb.btm_inq_vars.inq_db[inx]; inx < BTM_INQ_DB_SIZE; inx++, p_ent++)
        {
            if(p_ent->in_use)
            {
                return (&p_ent->inq_info);
            }
        }

        /* If here, more entries found */
        return ((tBTM_INQ_INFO *)NULL);
    }
    else
    {
        return (BTM_InqDbFirst());
    }
}


/*******************************************************************************
**
** Function         BTM_ClearInqDb
**
** Description      This function is called to clear out a device or all devices
**                  from the inquiry database.
**
** Parameter        p_bda - (input) BD_ADDR ->  Address of device to clear
**                                              (NULL clears all entries)
**
** Returns          BTM_BUSY if an inquiry, get remote name, or event filter
**                          is active, otherwise BTM_SUCCESS
**
*******************************************************************************/
tBTM_STATUS BTM_ClearInqDb(BD_ADDR p_bda)
{
    tBTM_INQUIRY_VAR_ST     *p_inq = &btm_cb.btm_inq_vars;

    /* If an inquiry or remote name is in progress return busy */
    if(p_inq->inq_active != BTM_INQUIRY_INACTIVE ||
            p_inq->inqfilt_active)
    {
        return (BTM_BUSY);
    }

    btm_clr_inq_db(p_bda);
    return (BTM_SUCCESS);
}

/*******************************************************************************
**
** Function         BTM_ReadInquiryRspTxPower
**
** Description      This command will read the inquiry Transmit Power level used
**                  to transmit the FHS and EIR data packets.
**                  This can be used directly in the Tx Power Level EIR data type.
**
** Returns          BTM_SUCCESS if successful
**
*******************************************************************************/
tBTM_STATUS BTM_ReadInquiryRspTxPower(tBTM_CMPL_CB *p_cb)
{
    if(btm_cb.devcb.p_inq_tx_power_cmpl_cb)
    {
        return (BTM_BUSY);
    }

    btm_cb.devcb.p_inq_tx_power_cmpl_cb = p_cb;
    #ifdef USE_ALARM
    alarm_set_on_queue(btm_cb.devcb.read_inq_tx_power_timer,
                       BTM_INQ_REPLY_TIMEOUT_MS,
                       btm_read_inq_tx_power_timeout, NULL,
                       btu_general_alarm_queue);
    #else
    btm_cb.devcb.read_inq_tx_power_timer.param = (TIMER_PARAM_TYPE)NULL;
    btm_cb.devcb.read_inq_tx_power_timer.p_cback = (TIMER_CBACK *)&btm_read_inq_tx_power_timeout;
    btu_start_timer(&btm_cb.devcb.read_inq_tx_power_timer, BTU_TTYPE_BTM_ACL, BTM_INQ_REPLY_TIMEOUT_MS / 1000);
    #endif

    if(!btsnd_hcic_read_inq_tx_power())
    {
        btm_cb.devcb.p_inq_tx_power_cmpl_cb = NULL;
        #ifdef USE_ALARM
        alarm_cancel(btm_cb.devcb.read_inq_tx_power_timer);
        #else
        btu_stop_timer(&btm_cb.devcb.read_inq_tx_power_timer);
        #endif
        return (BTM_NO_RESOURCES);
    }
    else
    {
        return (BTM_CMD_STARTED);
    }
}

/*********************************************************************************
**********************************************************************************
**                                                                              **
**                      BTM Internal Inquiry Functions                          **
**                                                                              **
**********************************************************************************
*********************************************************************************/
/*******************************************************************************
**
** Function         btm_inq_db_reset
**
** Description      This function is called at at reset to clear the inquiry
**                  database & pending callback.
**
** Returns          void
**
*******************************************************************************/
void btm_inq_db_reset(void)
{
    tBTM_REMOTE_DEV_NAME     rem_name;
    tBTM_INQUIRY_VAR_ST     *p_inq = &btm_cb.btm_inq_vars;
    uint8_t                    num_responses;
    uint8_t                    temp_inq_active;
    tBTM_STATUS              status;

    /* If an inquiry or periodic inquiry is active, reset the mode to inactive */
    if(p_inq->inq_active != BTM_INQUIRY_INACTIVE)
    {
        temp_inq_active = p_inq->inq_active;    /* Save so state can change BEFORE
                                                       callback is called */
        p_inq->inq_active = BTM_INQUIRY_INACTIVE;

        /* If not a periodic inquiry, the complete callback must be called to notify caller */
        if(temp_inq_active == BTM_LIMITED_INQUIRY_ACTIVE ||
                temp_inq_active == BTM_GENERAL_INQUIRY_ACTIVE)
        {
            if(p_inq->p_inq_cmpl_cb)
            {
                num_responses = 0;
                (*p_inq->p_inq_cmpl_cb)(&num_responses);
            }
        }
    }

    /* Cancel a remote name request if active, and notify the caller (if waiting) */
    if(p_inq->remname_active)
    {
        #ifdef USE_ALARM
        alarm_cancel(p_inq->remote_name_timer);
        #else
        btu_stop_timer(&p_inq->remote_name_timer);
        #endif
        p_inq->remname_active = FALSE;
        wm_memset(p_inq->remname_bda, 0, BD_ADDR_LEN);

        if(p_inq->p_remname_cmpl_cb)
        {
            rem_name.status = BTM_DEV_RESET;
            (*p_inq->p_remname_cmpl_cb)(&rem_name);
            p_inq->p_remname_cmpl_cb = NULL;
        }
    }

    /* Cancel an inquiry filter request if active, and notify the caller (if waiting) */
    if(p_inq->inqfilt_active)
    {
        p_inq->inqfilt_active = FALSE;

        if(p_inq->p_inqfilter_cmpl_cb)
        {
            status = BTM_DEV_RESET;
            (*p_inq->p_inqfilter_cmpl_cb)(&status);
        }
    }

    p_inq->state = BTM_INQ_INACTIVE_STATE;
    p_inq->pending_filt_complete_event = 0;
    p_inq->p_inq_results_cb = NULL;
    btm_clr_inq_db(NULL);   /* Clear out all the entries in the database */
    btm_clr_inq_result_flt();
    p_inq->discoverable_mode = BTM_NON_DISCOVERABLE;
    p_inq->connectable_mode  = BTM_NON_CONNECTABLE;
    p_inq->page_scan_type    = BTM_SCAN_TYPE_STANDARD;
    p_inq->inq_scan_type     = BTM_SCAN_TYPE_STANDARD;
    #if BLE_INCLUDED == TRUE
    p_inq->discoverable_mode |= BTM_BLE_NON_DISCOVERABLE;
    p_inq->connectable_mode  |= BTM_BLE_NON_CONNECTABLE;
    #endif
    return;
}


/*********************************************************************************
**
** Function         btm_inq_db_init
**
** Description      This function is called at startup to initialize the inquiry
**                  database.
**
** Returns          void
**
*******************************************************************************/
void btm_inq_db_init(void)
{
    #if 0  /* cleared in btm_init; put back in if called from anywhere else! */
    wm_memset(&btm_cb.btm_inq_vars, 0, sizeof(tBTM_INQUIRY_VAR_ST));
    #endif
    #ifdef USE_ALARM
    alarm_free(btm_cb.btm_inq_vars.remote_name_timer);
    btm_cb.btm_inq_vars.remote_name_timer =
                    alarm_new("btm_inq.remote_name_timer");
    #endif
    btm_cb.btm_inq_vars.no_inc_ssp = BTM_NO_SSP_ON_INQUIRY;
}

/*********************************************************************************
**
** Function         btm_inq_stop_on_ssp
**
** Description      This function is called on incoming SSP
**
** Returns          void
**
*******************************************************************************/
void btm_inq_stop_on_ssp(void)
{
    uint8_t normal_active = (BTM_GENERAL_INQUIRY_ACTIVE | BTM_LIMITED_INQUIRY_ACTIVE);
    #if (BTM_INQ_DEBUG == TRUE)
    BTM_TRACE_DEBUG("btm_inq_stop_on_ssp: no_inc_ssp=%d inq_active:0x%x state:%d inqfilt_active:%d",
                    btm_cb.btm_inq_vars.no_inc_ssp, btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active);
    #endif

    if(btm_cb.btm_inq_vars.no_inc_ssp)
    {
        if(btm_cb.btm_inq_vars.state == BTM_INQ_ACTIVE_STATE)
        {
            if(btm_cb.btm_inq_vars.inq_active & BTM_PERIODIC_INQUIRY_ACTIVE)
            {
                BTM_CancelPeriodicInquiry();
            }
            else
                if(btm_cb.btm_inq_vars.inq_active & normal_active)
                {
                    /* can not call BTM_CancelInquiry() here. We need to report inquiry complete evt */
                    btsnd_hcic_inq_cancel();
                }
        }

        /* do not allow inquiry to start */
        btm_cb.btm_inq_vars.inq_active |= BTM_SSP_INQUIRY_ACTIVE;
    }
}

/*********************************************************************************
**
** Function         btm_inq_clear_ssp
**
** Description      This function is called when pairing_state becomes idle
**
** Returns          void
**
*******************************************************************************/
void btm_inq_clear_ssp(void)
{
    btm_cb.btm_inq_vars.inq_active &= ~BTM_SSP_INQUIRY_ACTIVE;
}

/*********************************************************************************
**
** Function         btm_clr_inq_db
**
** Description      This function is called to clear out a device or all devices
**                  from the inquiry database.
**
** Parameter        p_bda - (input) BD_ADDR ->  Address of device to clear
**                                              (NULL clears all entries)
**
** Returns          void
**
*******************************************************************************/
void btm_clr_inq_db(BD_ADDR p_bda)
{
    tBTM_INQUIRY_VAR_ST     *p_inq = &btm_cb.btm_inq_vars;
    tINQ_DB_ENT             *p_ent = p_inq->inq_db;
    uint16_t                   xx;
    #if (BTM_INQ_DEBUG == TRUE)
    BTM_TRACE_DEBUG("btm_clr_inq_db: inq_active:0x%x state:%d",
                    btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state);
    #endif

    for(xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++)
    {
        if(p_ent->in_use)
        {
            /* If this is the specified BD_ADDR or clearing all devices */
            if(p_bda == NULL ||
                    (!memcmp(p_ent->inq_info.results.remote_bd_addr, p_bda, BD_ADDR_LEN)))
            {
                p_ent->in_use = FALSE;
            }
        }
    }

    #if (BTM_INQ_DEBUG == TRUE)
    BTM_TRACE_DEBUG("inq_active:0x%x state:%d",
                    btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state);
    #endif
}


/*******************************************************************************
**
** Function         btm_clr_inq_result_flt
**
** Description      This function looks through the bdaddr database for a match
**                  based on Bluetooth Device Address
**
** Returns          TRUE if found, else FALSE (new entry)
**
*******************************************************************************/
static void btm_clr_inq_result_flt(void)
{
    tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;

    if(p_inq->p_bd_db)
    {
        GKI_free_and_reset_buf((void **)&p_inq->p_bd_db);
    }

    p_inq->num_bd_entries = 0;
    p_inq->max_bd_entries = 0;
}

/*******************************************************************************
**
** Function         btm_inq_find_bdaddr
**
** Description      This function looks through the bdaddr database for a match
**                  based on Bluetooth Device Address
**
** Returns          TRUE if found, else FALSE (new entry)
**
*******************************************************************************/
uint8_t btm_inq_find_bdaddr(BD_ADDR p_bda)
{
    tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
    tINQ_BDADDR         *p_db = &p_inq->p_bd_db[0];
    uint16_t       xx;

    /* Don't bother searching, database doesn't exist or periodic mode */
    if((p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) || !p_db)
    {
        return (FALSE);
    }

    for(xx = 0; xx < p_inq->num_bd_entries; xx++, p_db++)
    {
        if(!memcmp(p_db->bd_addr, p_bda, BD_ADDR_LEN)
                && p_db->inq_count == p_inq->inq_counter)
        {
            return (TRUE);
        }
    }

    if(xx < p_inq->max_bd_entries)
    {
        p_db->inq_count = p_inq->inq_counter;
        wm_memcpy(p_db->bd_addr, p_bda, BD_ADDR_LEN);
        p_inq->num_bd_entries++;
    }

    /* If here, New Entry */
    return (FALSE);
}

/*******************************************************************************
**
** Function         btm_inq_db_find
**
** Description      This function looks through the inquiry database for a match
**                  based on Bluetooth Device Address
**
** Returns          pointer to entry, or NULL if not found
**
*******************************************************************************/
tINQ_DB_ENT *btm_inq_db_find(BD_ADDR p_bda)
{
    uint16_t       xx;
    tINQ_DB_ENT  *p_ent = btm_cb.btm_inq_vars.inq_db;

    for(xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++)
    {
        if((p_ent->in_use) && (!memcmp(p_ent->inq_info.results.remote_bd_addr, p_bda, BD_ADDR_LEN)))
        {
            return (p_ent);
        }
    }

    /* If here, not found */
    return (NULL);
}


/*******************************************************************************
**
** Function         btm_inq_db_new
**
** Description      This function looks through the inquiry database for an unused
**                  entry. If no entry is free, it allocates the oldest entry.
**
** Returns          pointer to entry
**
*******************************************************************************/
tINQ_DB_ENT *btm_inq_db_new(BD_ADDR p_bda)
{
    uint16_t       xx;
    tINQ_DB_ENT  *p_ent = btm_cb.btm_inq_vars.inq_db;
    tINQ_DB_ENT  *p_old = btm_cb.btm_inq_vars.inq_db;
    uint32_t       ot = 0xFFFFFFFF;

    for(xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++)
    {
        if(!p_ent->in_use)
        {
            wm_memset(p_ent, 0, sizeof(tINQ_DB_ENT));
            wm_memcpy(p_ent->inq_info.results.remote_bd_addr, p_bda, BD_ADDR_LEN);
            p_ent->in_use = TRUE;
            return (p_ent);
        }

        if(p_ent->time_of_resp < ot)
        {
            p_old = p_ent;
            ot    = p_ent->time_of_resp;
        }
    }

    /* If here, no free entry found. Return the oldest. */
    wm_memset(p_old, 0, sizeof(tINQ_DB_ENT));
    wm_memcpy(p_old->inq_info.results.remote_bd_addr, p_bda, BD_ADDR_LEN);
    p_old->in_use = TRUE;
    return (p_old);
}


/*******************************************************************************
**
** Function         btm_set_inq_event_filter
**
** Description      This function is called to set the inquiry event filter.
**                  It is called by either internally, or by the external API function
**                  (BTM_SetInqEventFilter).  It is used internally as part of the
**                  inquiry processing.
**
** Input Params:
**                  filter_cond_type - this is the type of inquiry filter to apply:
**                          BTM_FILTER_COND_DEVICE_CLASS,
**                          BTM_FILTER_COND_BD_ADDR, or
**                          BTM_CLR_INQUIRY_FILTER
**
**                  p_filt_cond - this is either a BD_ADDR or DEV_CLASS depending on the
**                          filter_cond_type  (See section 4.7.3 of Core Spec 1.0b).
**
** Returns          BTM_CMD_STARTED if successfully initiated
**                  BTM_NO_RESOURCES if couldn't get a memory pool buffer
**                  BTM_ILLEGAL_VALUE if a bad parameter was detected
**
*******************************************************************************/
static tBTM_STATUS btm_set_inq_event_filter(uint8_t filter_cond_type,
        tBTM_INQ_FILT_COND *p_filt_cond)
{
    uint8_t    condition_length = DEV_CLASS_LEN * 2;
    uint8_t    condition_buf[DEV_CLASS_LEN * 2];
    uint8_t   *p_cond = condition_buf;                    /* points to the condition to pass to HCI */
    #if (BTM_INQ_DEBUG == TRUE)
    BTM_TRACE_DEBUG("btm_set_inq_event_filter: filter type %d [Clear-0, COD-1, BDADDR-2]",
                    filter_cond_type);
    BTM_TRACE_DEBUG("                       condition [%02x%02x%02x %02x%02x%02x]",
                    p_filt_cond->bdaddr_cond[0], p_filt_cond->bdaddr_cond[1], p_filt_cond->bdaddr_cond[2],
                    p_filt_cond->bdaddr_cond[3], p_filt_cond->bdaddr_cond[4], p_filt_cond->bdaddr_cond[5]);
    #endif

    /* Load the correct filter condition to pass to the lower layer */
    switch(filter_cond_type)
    {
        case BTM_FILTER_COND_DEVICE_CLASS:
            /* copy the device class and device class fields into contiguous memory to send to HCI */
            wm_memcpy(condition_buf, p_filt_cond->cod_cond.dev_class, DEV_CLASS_LEN);
            wm_memcpy(&condition_buf[DEV_CLASS_LEN],
                      p_filt_cond->cod_cond.dev_class_mask, DEV_CLASS_LEN);
            /* condition length should already be set as the default */
            break;

        case BTM_FILTER_COND_BD_ADDR:
            p_cond = p_filt_cond->bdaddr_cond;
            /* condition length should already be set as the default */
            break;

        case BTM_CLR_INQUIRY_FILTER:
            condition_length = 0;
            break;

        default:
            return (BTM_ILLEGAL_VALUE);     /* Bad parameter was passed in */
    }

    btm_cb.btm_inq_vars.inqfilt_active = TRUE;

    /* Filter the inquiry results for the specified condition type and value */
    if(btsnd_hcic_set_event_filter(HCI_FILTER_INQUIRY_RESULT, filter_cond_type,
                                   p_cond, condition_length))
    {
        return (BTM_CMD_STARTED);
    }
    else
    {
        return (BTM_NO_RESOURCES);
    }
}


/*******************************************************************************
**
** Function         btm_event_filter_complete
**
** Description      This function is called when a set event filter has completed.
**                  Note: This routine currently only handles inquiry filters.
**                      Connection filters are ignored for now.
**
** Returns          void
**
*******************************************************************************/
void btm_event_filter_complete(uint8_t *p)
{
    uint8_t            hci_status;
    tBTM_STATUS      status;
    tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
    tBTM_CMPL_CB   *p_cb = p_inq->p_inqfilter_cmpl_cb;
    #if (BTM_INQ_DEBUG == TRUE)
    BTM_TRACE_DEBUG("btm_event_filter_complete: inq_active:0x%x state:%d inqfilt_active:%d",
                    btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active);
    #endif

    /* If the filter complete event is from an old or cancelled request, ignore it */
    if(p_inq->pending_filt_complete_event)
    {
        p_inq->pending_filt_complete_event--;
        return;
    }

    /* Only process the inquiry filter; Ignore the connection filter until it
       is used by the upper layers */
    if(p_inq->inqfilt_active == TRUE)
    {
        /* Extract the returned status from the buffer */
        STREAM_TO_UINT8(hci_status, p);

        if(hci_status != HCI_SUCCESS)
        {
            /* If standalone operation, return the error status; if embedded in the inquiry, continue the inquiry */
            BTM_TRACE_WARNING("BTM Warning: Set Event Filter Failed (HCI returned 0x%x)", hci_status);
            status = BTM_ERR_PROCESSING;
        }
        else
        {
            status = BTM_SUCCESS;
        }

        /* If the set filter was initiated externally (via BTM_SetInqEventFilter), call the
           callback function to notify the initiator that it has completed */
        if(p_inq->state == BTM_INQ_INACTIVE_STATE)
        {
            p_inq->inqfilt_active = FALSE;

            if(p_cb)
            {
                (*p_cb)(&status);
            }
        }
        else    /* An inquiry is active (the set filter command was internally generated),
                   process the next state of the process (Set a new filter or start the inquiry). */
        {
            if(status != BTM_SUCCESS)
            {
                /* Process the inquiry complete (Error Status) */
                btm_process_inq_complete(BTM_ERR_PROCESSING, (uint8_t)(p_inq->inqparms.mode & BTM_BR_INQUIRY_MASK));
                /* btm_process_inq_complete() does not restore the following settings on periodic inquiry */
                p_inq->inqfilt_active = FALSE;
                p_inq->inq_active = BTM_INQUIRY_INACTIVE;
                p_inq->state = BTM_INQ_INACTIVE_STATE;
                return;
            }

            /* Check to see if a new filter needs to be set up */
            if(p_inq->state == BTM_INQ_CLR_FILT_STATE)
            {
                if((status = btm_set_inq_event_filter(p_inq->inqparms.filter_cond_type, &p_inq->inqparms.filter_cond)) == BTM_CMD_STARTED)
                {
                    p_inq->state = BTM_INQ_SET_FILT_STATE;
                }
                else    /* Error setting the filter: Call the initiator's callback function to indicate a failure */
                {
                    p_inq->inqfilt_active = FALSE;
                    /* Process the inquiry complete (Error Status) */
                    btm_process_inq_complete(BTM_ERR_PROCESSING, (uint8_t)(p_inq->inqparms.mode & BTM_BR_INQUIRY_MASK));
                }
            }
            else    /* Initiate the Inquiry or Periodic Inquiry */
            {
                p_inq->state = BTM_INQ_ACTIVE_STATE;
                p_inq->inqfilt_active = FALSE;
                btm_initiate_inquiry(p_inq);
            }
        }
    }
}


/*******************************************************************************
**
** Function         btm_initiate_inquiry
**
** Description      This function is called to start an inquiry or periodic inquiry
**                  upon completion of the setting and/or clearing of the inquiry filter.
**
** Inputs:          p_inq (btm_cb.btm_inq_vars) - pointer to saved inquiry information
**                      mode - GENERAL or LIMITED inquiry
**                      duration - length in 1.28 sec intervals (If '0', the inquiry is CANCELLED)
**                      max_resps - maximum amount of devices to search for before ending the inquiry
**                      filter_cond_type - BTM_CLR_INQUIRY_FILTER, BTM_FILTER_COND_DEVICE_CLASS, or
**                                         BTM_FILTER_COND_BD_ADDR
**                      filter_cond - value for the filter (based on filter_cond_type)
**
** Returns          If an error occurs the initiator's callback is called with the error status.
**
*******************************************************************************/
static void btm_initiate_inquiry(tBTM_INQUIRY_VAR_ST *p_inq)
{
    const LAP       *lap;
    tBTM_INQ_PARMS  *p_inqparms = &p_inq->inqparms;
    #if (BTM_INQ_DEBUG == TRUE)
    BTM_TRACE_DEBUG("btm_initiate_inquiry: inq_active:0x%x state:%d inqfilt_active:%d",
                    btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active);
    #endif
    btm_acl_update_busy_level(BTM_BLI_INQ_EVT);

    if(p_inq->inq_active & BTM_SSP_INQUIRY_ACTIVE)
    {
        btm_process_inq_complete(BTM_NO_RESOURCES, (uint8_t)(p_inqparms->mode & BTM_BR_INQUIRY_MASK));
        return;
    }

    /* Make sure the number of responses doesn't overflow the database configuration */
    p_inqparms->max_resps = (uint8_t)((p_inqparms->max_resps <= BTM_INQ_DB_SIZE) ? p_inqparms->max_resps : BTM_INQ_DB_SIZE);
    lap = (p_inq->inq_active & BTM_LIMITED_INQUIRY_ACTIVE) ? &limited_inq_lap : &general_inq_lap;

    if(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE)
    {
        if(!btsnd_hcic_per_inq_mode(p_inq->per_max_delay,
                                    p_inq->per_min_delay,
                                    *lap, p_inqparms->duration,
                                    p_inqparms->max_resps))
        {
            btm_process_inq_complete(BTM_NO_RESOURCES, (uint8_t)(p_inqparms->mode & BTM_BR_INQUIRY_MASK));
        }
    }
    else
    {
        btm_clr_inq_result_flt();
        /* Allocate memory to hold bd_addrs responding */
        p_inq->p_bd_db = (tINQ_BDADDR *)GKI_getbuf(BT_DEFAULT_BUFFER_SIZE);
        p_inq->max_bd_entries = (uint16_t)(BT_DEFAULT_BUFFER_SIZE / sizeof(tINQ_BDADDR));

        if(!btsnd_hcic_inquiry(*lap, p_inqparms->duration, 0))
        {
            btm_process_inq_complete(BTM_NO_RESOURCES, (uint8_t)(p_inqparms->mode & BTM_BR_INQUIRY_MASK));
        }
    }
}

/*******************************************************************************
**
** Function         btm_process_inq_results
**
** Description      This function is called when inquiry results are received from
**                  the device. It updates the inquiry database. If the inquiry
**                  database is full, the oldest entry is discarded.
**
** Parameters       inq_res_mode - BTM_INQ_RESULT_STANDARD
**                                 BTM_INQ_RESULT_WITH_RSSI
**                                 BTM_INQ_RESULT_EXTENDED
**
** Returns          void
**
*******************************************************************************/
void btm_process_inq_results(uint8_t *p, uint8_t inq_res_mode)
{
    uint8_t            num_resp, xx;
    BD_ADDR          bda;
    tINQ_DB_ENT     *p_i;
    tBTM_INQ_RESULTS *p_cur = NULL;
    uint8_t          is_new = TRUE;
    uint8_t          update = FALSE;
    int8_t             i_rssi;
    tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
    tBTM_INQ_RESULTS_CB *p_inq_results_cb = p_inq->p_inq_results_cb;
    uint8_t            page_scan_rep_mode = 0;
    uint8_t            page_scan_per_mode = 0;
    uint8_t            page_scan_mode = 0;
    uint8_t            rssi = 0;
    DEV_CLASS        dc;
    uint16_t           clock_offset;
    uint8_t            *p_eir_data = NULL;
    #if (BTM_INQ_DEBUG == TRUE)
    BTM_TRACE_DEBUG("btm_process_inq_results inq_active:0x%x state:%d inqfilt_active:%d",
                    btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active);
    #endif

    /* Only process the results if the BR inquiry is still active */
    if(!(p_inq->inq_active & BTM_BR_INQ_ACTIVE_MASK))
    {
        return;
    }

    STREAM_TO_UINT8(num_resp, p);

    if(inq_res_mode == BTM_INQ_RESULT_EXTENDED && (num_resp > 1))
    {
        BTM_TRACE_ERROR("btm_process_inq_results() extended results (%d) > 1",
                        num_resp);
        return;
    }

    for(xx = 0; xx < num_resp; xx++)
    {
        update = FALSE;
        /* Extract inquiry results */
        STREAM_TO_BDADDR(bda, p);
        STREAM_TO_UINT8(page_scan_rep_mode, p);
        STREAM_TO_UINT8(page_scan_per_mode, p);

        if(inq_res_mode == BTM_INQ_RESULT_STANDARD)
        {
            STREAM_TO_UINT8(page_scan_mode, p);
        }

        STREAM_TO_DEVCLASS(dc, p);
        STREAM_TO_UINT16(clock_offset, p);

        if(inq_res_mode != BTM_INQ_RESULT_STANDARD)
        {
            STREAM_TO_UINT8(rssi, p);
        }

        p_i = btm_inq_db_find(bda);

        /* Only process the num_resp is smaller than max_resps.
           If results are queued to BTU task while canceling inquiry,
           or when more than one result is in this response, > max_resp
           responses could be processed which can confuse some apps
        */
        if(p_inq->inqparms.max_resps &&
                p_inq->inq_cmpl_info.num_resp >= p_inq->inqparms.max_resps
            #if BLE_INCLUDED == TRUE
                /* new device response */
                && (p_i == NULL ||
                    /* exisiting device with BR/EDR info */
                    (p_i && (p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BREDR) != 0)
                   )
            #endif
          )
        {
            /*            BTM_TRACE_WARNING("INQ RES: Extra Response Received...ignoring"); */
            return;
        }

        /* Check if this address has already been processed for this inquiry */
        if(btm_inq_find_bdaddr(bda))
        {
            /*             BTM_TRACE_DEBUG("BDA seen before [%02x%02x %02x%02x %02x%02x]",
                                         bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);*/
            /* By default suppose no update needed */
            i_rssi = (int8_t)rssi;

            /* If this new RSSI is higher than the last one */
            if(p_inq->inqparms.report_dup && (rssi != 0) &&
                    p_i && (i_rssi > p_i->inq_info.results.rssi || p_i->inq_info.results.rssi == 0
                        #if BLE_INCLUDED == TRUE
                            /* BR/EDR inquiry information update */
                            || (p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BREDR) != 0
                        #endif
                           ))
            {
                p_cur = &p_i->inq_info.results;
                BTM_TRACE_DEBUG("update RSSI new:%d, old:%d", i_rssi, p_cur->rssi);
                p_cur->rssi = i_rssi;
                update = TRUE;
            }
            /* If we received a second Extended Inq Event for an already */
            /* discovered device, this is because for the first one EIR was not received */
            else
                if((inq_res_mode == BTM_INQ_RESULT_EXTENDED) && (p_i))
                {
                    p_cur = &p_i->inq_info.results;
                    update = TRUE;
                }
                /* If no update needed continue with next response (if any) */
                else
                {
                    continue;
                }
        }

        /* If existing entry, use that, else get a new one (possibly reusing the oldest) */
        if(p_i == NULL)
        {
            p_i = btm_inq_db_new(bda);
            is_new = TRUE;
        }
        /* If an entry for the device already exists, overwrite it ONLY if it is from
           a previous inquiry. (Ignore it if it is a duplicate response from the same
           inquiry.
        */
        else
            if(p_i->inq_count == p_inq->inq_counter
                #if (BLE_INCLUDED == TRUE )
                    && (p_i->inq_info.results.device_type == BT_DEVICE_TYPE_BREDR)
                #endif
              )
            {
                is_new = FALSE;
            }

        /* keep updating RSSI to have latest value */
        if(inq_res_mode != BTM_INQ_RESULT_STANDARD)
        {
            p_i->inq_info.results.rssi = (int8_t)rssi;
        }
        else
        {
            p_i->inq_info.results.rssi = BTM_INQ_RES_IGNORE_RSSI;
        }

        if(is_new == TRUE)
        {
            /* Save the info */
            p_cur = &p_i->inq_info.results;
            p_cur->page_scan_rep_mode = page_scan_rep_mode;
            p_cur->page_scan_per_mode = page_scan_per_mode;
            p_cur->page_scan_mode     = page_scan_mode;
            p_cur->dev_class[0]       = dc[0];
            p_cur->dev_class[1]       = dc[1];
            p_cur->dev_class[2]       = dc[2];
            p_cur->clock_offset       = clock_offset  | BTM_CLOCK_OFFSET_VALID;
            p_i->time_of_resp = GKI_time_get_os_boottime_ms();

            if(p_i->inq_count != p_inq->inq_counter)
            {
                p_inq->inq_cmpl_info.num_resp++;    /* A new response was found */
            }

            #if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE)
            p_cur->inq_result_type    = BTM_INQ_RESULT_BR;

            if(p_i->inq_count != p_inq->inq_counter)
            {
                p_cur->device_type  = BT_DEVICE_TYPE_BREDR;
                p_i->scan_rsp       = FALSE;
            }
            else
            {
                p_cur->device_type    |= BT_DEVICE_TYPE_BREDR;
            }

            #endif
            p_i->inq_count = p_inq->inq_counter;   /* Mark entry for current inquiry */

            /* If the number of responses found and not unlimited, issue a cancel inquiry */
            if(!(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) &&
                    p_inq->inqparms.max_resps &&
                    p_inq->inq_cmpl_info.num_resp == p_inq->inqparms.max_resps
                #if BLE_INCLUDED == TRUE
                    /* BLE scanning is active and received adv */
                    && ((((p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) != 0) &&
                         p_cur->device_type == BT_DEVICE_TYPE_DUMO && p_i->scan_rsp) ||
                        (p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) == 0)
                #endif
              )
            {
                /*                BTM_TRACE_DEBUG("BTMINQ: Found devices, cancelling inquiry..."); */
                btsnd_hcic_inq_cancel();
                #if BLE_INCLUDED == TRUE

                if((p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) != 0)
                {
                    btm_ble_stop_inquiry();
                }

                #endif
                btm_acl_update_busy_level(BTM_BLI_INQ_DONE_EVT);
            }

            /* Initialize flag to FALSE. This flag is set/used by application */
            p_i->inq_info.appl_knows_rem_name = FALSE;
        }

        if(is_new || update)
        {
            if(inq_res_mode == BTM_INQ_RESULT_EXTENDED)
            {
                wm_memset(p_cur->eir_uuid, 0,
                          BTM_EIR_SERVICE_ARRAY_SIZE * (BTM_EIR_ARRAY_BITS / 8));
                /* set bit map of UUID list from received EIR */
                btm_set_eir_uuid(p, p_cur);
                p_eir_data = p;
            }
            else
            {
                p_eir_data = NULL;
            }

            /* If a callback is registered, call it with the results */
            if(p_inq_results_cb)
            {
                (p_inq_results_cb)((tBTM_INQ_RESULTS *) p_cur, p_eir_data);
            }
        }
    }
}

/*******************************************************************************
**
** Function         btm_sort_inq_result
**
** Description      This function is called when inquiry complete is received
**                  from the device to sort inquiry results based on rssi.
**
** Returns          void
**
*******************************************************************************/
void btm_sort_inq_result(void)
{
    uint8_t xx, yy, num_resp;
    tINQ_DB_ENT *p_ent  = btm_cb.btm_inq_vars.inq_db;
    tINQ_DB_ENT *p_next = btm_cb.btm_inq_vars.inq_db + 1;
    int size;
    tINQ_DB_ENT *p_tmp = (tINQ_DB_ENT *)GKI_getbuf(sizeof(tINQ_DB_ENT));
    num_resp = (btm_cb.btm_inq_vars.inq_cmpl_info.num_resp < BTM_INQ_DB_SIZE) ?
               btm_cb.btm_inq_vars.inq_cmpl_info.num_resp : BTM_INQ_DB_SIZE;
    size = sizeof(tINQ_DB_ENT);

    for(xx = 0; xx < num_resp - 1; xx++, p_ent++)
    {
        for(yy = xx + 1, p_next = p_ent + 1; yy < num_resp; yy++, p_next++)
        {
            if(p_ent->inq_info.results.rssi < p_next->inq_info.results.rssi)
            {
                wm_memcpy(p_tmp, p_next, size);
                wm_memcpy(p_next, p_ent,  size);
                wm_memcpy(p_ent, p_tmp,  size);
            }
        }
    }

    GKI_freebuf(p_tmp);
}

/*******************************************************************************
**
** Function         btm_process_inq_complete
**
** Description      This function is called when inquiry complete is received
**                  from the device.  Call the callback if not in periodic inquiry
**                  mode AND it is not NULL (The caller wants the event).
**
**                  The callback pass back the status and the number of responses
**
** Returns          void
**
*******************************************************************************/
void btm_process_inq_complete(uint8_t status, uint8_t mode)
{
    tBTM_CMPL_CB        *p_inq_cb = btm_cb.btm_inq_vars.p_inq_cmpl_cb;
    tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
    #if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE)

    /* inquiry inactive case happens when inquiry is cancelled.
       Make mode 0 for no further inquiries from the current inquiry process
    */
    if(status != HCI_SUCCESS || p_inq->next_state == BTM_FINISH || !p_inq->inq_active)
    {
        /* re-initialize for next inquiry request */
        p_inq->next_state = BTM_BR_ONE;
        /* make the mode 0 here */
        p_inq->inqparms.mode &= ~(p_inq->inqparms.mode);
    }

    #endif
    #if (!defined(BTA_HOST_INTERLEAVE_SEARCH) || BTA_HOST_INTERLEAVE_SEARCH == FALSE)
    p_inq->inqparms.mode &= ~(mode);
    #endif

    if(p_inq->scan_type == INQ_LE_OBSERVE && !p_inq->inq_active)
    {
        /*end of LE observe*/
        p_inq->p_inq_ble_results_cb = (tBTM_INQ_RESULTS_CB *) NULL;
        p_inq->p_inq_ble_cmpl_cb = (tBTM_CMPL_CB *) NULL;
        p_inq->scan_type = INQ_NONE;
    }

    #if (BTM_INQ_DEBUG == TRUE)
    BTM_TRACE_DEBUG("btm_process_inq_complete inq_active:0x%x state:%d inqfilt_active:%d",
                    btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active);
    #endif
    btm_acl_update_busy_level(BTM_BLI_INQ_DONE_EVT);

    /* Ignore any stray or late complete messages if the inquiry is not active */
    if(p_inq->inq_active)
    {
        p_inq->inq_cmpl_info.status = (tBTM_STATUS)((status == HCI_SUCCESS) ? BTM_SUCCESS : BTM_ERR_PROCESSING);

        /* Notify caller that the inquiry has completed; (periodic inquiries do not send completion events */
        if(!(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) && p_inq->inqparms.mode == 0)
        {
            #if BLE_INCLUDED == TRUE
            btm_clear_all_pending_le_entry();
            #endif
            p_inq->state = BTM_INQ_INACTIVE_STATE;
            /* Increment so the start of a next inquiry has a new count */
            p_inq->inq_counter++;
            btm_clr_inq_result_flt();

            if((p_inq->inq_cmpl_info.status == BTM_SUCCESS) &&
                    HCI_LMP_INQ_RSSI_SUPPORTED(btm_cb.devcb.local_lmp_features[HCI_EXT_FEATURES_PAGE_0]))
            {
                btm_sort_inq_result();
            }

            /* Clear the results callback if set */
            p_inq->p_inq_results_cb = (tBTM_INQ_RESULTS_CB *) NULL;
            p_inq->inq_active = BTM_INQUIRY_INACTIVE;
            p_inq->p_inq_cmpl_cb = (tBTM_CMPL_CB *) NULL;
            /* If we have a callback registered for inquiry complete, call it */
            BTM_TRACE_DEBUG("BTM Inq Compl Callback: status 0x%02x, num results %d",
                            p_inq->inq_cmpl_info.status, p_inq->inq_cmpl_info.num_resp);

            if(p_inq_cb)
            {
                (p_inq_cb)((tBTM_INQUIRY_CMPL *) &p_inq->inq_cmpl_info);
            }
        }

        #if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE)

        if(p_inq->inqparms.mode != 0 && !(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE))
        {
            /* make inquiry inactive for next iteration */
            p_inq->inq_active = BTM_INQUIRY_INACTIVE;
            /* call the inquiry again */
            BTM_StartInquiry(&p_inq->inqparms, p_inq->p_inq_results_cb, p_inq->p_inq_cmpl_cb);
        }

        #endif
    }

    if(p_inq->inqparms.mode == 0 && p_inq->scan_type == INQ_GENERAL)   //this inquiry is complete
    {
        p_inq->scan_type = INQ_NONE;
        #if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE)

        /* check if the LE observe is pending */
        if(p_inq->p_inq_ble_results_cb != NULL)
        {
            BTM_TRACE_DEBUG("BTM Inq Compl: resuming a pending LE scan");
            BTM_BleObserve(1, 0, p_inq->p_inq_ble_results_cb, p_inq->p_inq_ble_cmpl_cb);
        }

        #endif
    }

    #if (BTM_INQ_DEBUG == TRUE)
    BTM_TRACE_DEBUG("inq_active:0x%x state:%d inqfilt_active:%d",
                    btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active);
    #endif
}

/*******************************************************************************
**
** Function         btm_process_cancel_complete
**
** Description      This function is called when inquiry cancel complete is received
**                  from the device.This function will also call the btm_process_inq_complete
**                  This function is needed to differentiate a cancel_cmpl_evt from the
**                  inq_cmpl_evt
**
** Returns          void
**
*******************************************************************************/
void btm_process_cancel_complete(uint8_t status, uint8_t mode)
{
    btm_acl_update_busy_level(BTM_BLI_INQ_CANCEL_EVT);
    btm_process_inq_complete(status, mode);
}
/*******************************************************************************
**
** Function         btm_initiate_rem_name
**
** Description      This function looks initiates a remote name request.  It is called
**                  either by GAP or by the API call BTM_ReadRemoteDeviceName.
**
** Input Params:    p_cur         - pointer to an inquiry result structure (NULL if nonexistent)
**                  p_cb            - callback function called when BTM_CMD_STARTED
**                                    is returned.
**                                    A pointer to tBTM_REMOTE_DEV_NAME is passed to the
**                                    callback.
**
** Returns
**                  BTM_CMD_STARTED is returned if the request was sent to HCI.
**                  BTM_BUSY if already in progress
**                  BTM_NO_RESOURCES if could not allocate resources to start the command
**                  BTM_WRONG_MODE if the device is not up.
**
*******************************************************************************/
tBTM_STATUS  btm_initiate_rem_name(BD_ADDR remote_bda, tBTM_INQ_INFO *p_cur,
                                   uint8_t origin, uint64_t timeout_ms,
                                   tBTM_CMPL_CB *p_cb)
{
    tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
    uint8_t              cmd_ok;

    /*** Make sure the device is ready ***/
    if(!BTM_IsDeviceUp())
    {
        return (BTM_WRONG_MODE);
    }

    if(origin == BTM_RMT_NAME_SEC)
    {
        cmd_ok = btsnd_hcic_rmt_name_req(remote_bda, HCI_PAGE_SCAN_REP_MODE_R1,
                                         HCI_MANDATARY_PAGE_SCAN_MODE, 0);

        if(cmd_ok)
        {
            return BTM_CMD_STARTED;
        }
        else
        {
            return BTM_NO_RESOURCES;
        }
    }
    /* Make sure there are no two remote name requests from external API in progress */
    else
        if(origin == BTM_RMT_NAME_EXT)
        {
            if(p_inq->remname_active)
            {
                return (BTM_BUSY);
            }
            else
            {
                /* If there is no remote name request running,call the callback function and start timer */
                p_inq->p_remname_cmpl_cb = p_cb;
                wm_memcpy(p_inq->remname_bda, remote_bda, BD_ADDR_LEN);
                #ifdef USE_ALARM
                alarm_set_on_queue(p_inq->remote_name_timer, timeout_ms,
                                   btm_inq_remote_name_timer_timeout, NULL,
                                   btu_general_alarm_queue);
                #else
                p_inq->remote_name_timer.param = (TIMER_PARAM_TYPE)NULL;
                p_inq->remote_name_timer.p_cback = (TIMER_CBACK *)&btm_inq_remote_name_timer_timeout;
                btu_start_timer(&p_inq->remote_name_timer,
                                BTU_TTYPE_BTM_RMT_NAME,
                                timeout_ms / 1000);
                #endif

                /* If the database entry exists for the device, use its clock offset */
                if(p_cur)
                {
                    cmd_ok = btsnd_hcic_rmt_name_req(remote_bda,
                                                     p_cur->results.page_scan_rep_mode,
                                                     p_cur->results.page_scan_mode,
                                                     (uint16_t)(p_cur->results.clock_offset |
                                                             BTM_CLOCK_OFFSET_VALID));
                }
                else /* Otherwise use defaults and mark the clock offset as invalid */
                {
                    cmd_ok = btsnd_hcic_rmt_name_req(remote_bda, HCI_PAGE_SCAN_REP_MODE_R1,
                                                     HCI_MANDATARY_PAGE_SCAN_MODE, 0);
                }

                if(cmd_ok)
                {
                    p_inq->remname_active = TRUE;
                    return BTM_CMD_STARTED;
                }
                else
                {
                    return BTM_NO_RESOURCES;
                }
            }
        }
        else
        {
            return BTM_ILLEGAL_VALUE;
        }
}

/*******************************************************************************
**
** Function         btm_process_remote_name
**
** Description      This function is called when a remote name is received from
**                  the device. If remote names are cached, it updates the inquiry
**                  database.
**
** Returns          void
**
*******************************************************************************/
void btm_process_remote_name(BD_ADDR bda, BD_NAME bdn, uint16_t evt_len, uint8_t hci_status)
{
    tBTM_REMOTE_DEV_NAME    rem_name;
    tBTM_INQUIRY_VAR_ST    *p_inq = &btm_cb.btm_inq_vars;
    tBTM_CMPL_CB           *p_cb = p_inq->p_remname_cmpl_cb;
    uint8_t                  *p_n1;
    uint16_t                 temp_evt_len;

    if(bda != NULL)
    {
        BTM_TRACE_EVENT("BDA %02x:%02x:%02x:%02x:%02x:%02x", bda[0], bda[1],
                        bda[2], bda[3],
                        bda[4], bda[5]);
    }

    BTM_TRACE_EVENT("Inquire BDA %02x:%02x:%02x:%02x:%02x:%02x", p_inq->remname_bda[0], p_inq->remname_bda[1],
                    p_inq->remname_bda[2], p_inq->remname_bda[3],
                    p_inq->remname_bda[4], p_inq->remname_bda[5]);

    /* If the inquire BDA and remote DBA are the same, then stop the timer and set the active to false */
    if((p_inq->remname_active == TRUE) &&
            (((bda != NULL) &&
              (memcmp(bda, p_inq->remname_bda, BD_ADDR_LEN) == 0)) || bda == NULL))
    {
        #if BLE_INCLUDED == TRUE

        if(BTM_UseLeLink(p_inq->remname_bda))
        {
            if(hci_status == HCI_ERR_UNSPECIFIED)
            {
                btm_ble_cancel_remote_name(p_inq->remname_bda);
            }
        }

        #endif
        #ifdef USE_ALARM
        alarm_cancel(p_inq->remote_name_timer);
        #else
        btu_stop_timer(&p_inq->remote_name_timer);
        #endif
        p_inq->remname_active = FALSE;
        /* Clean up and return the status if the command was not successful */
        /* Note: If part of the inquiry, the name is not stored, and the    */
        /*       inquiry complete callback is called.                       */

        if(hci_status == HCI_SUCCESS)
        {
            /* Copy the name from the data stream into the return structure */
            /* Note that even if it is not being returned, it is used as a  */
            /*      temporary buffer.                                       */
            p_n1 = (uint8_t *)rem_name.remote_bd_name;
            rem_name.length = (evt_len < BD_NAME_LEN) ? evt_len : BD_NAME_LEN;
            rem_name.remote_bd_name[rem_name.length] = 0;
            rem_name.status = BTM_SUCCESS;
            temp_evt_len = rem_name.length;

            while(temp_evt_len > 0)
            {
                *p_n1++ = *bdn++;
                temp_evt_len--;
            }

            rem_name.remote_bd_name[rem_name.length] = 0;
        }
        /* If processing a stand alone remote name then report the error in the callback */
        else
        {
            rem_name.status = BTM_BAD_VALUE_RET;
            rem_name.length = 0;
            rem_name.remote_bd_name[0] = 0;
        }

        /* Reset the remote BAD to zero and call callback if possible */
        wm_memset(p_inq->remname_bda, 0, BD_ADDR_LEN);
        p_inq->p_remname_cmpl_cb = NULL;

        if(p_cb)
        {
            (p_cb)((tBTM_REMOTE_DEV_NAME *)&rem_name);
        }
    }
}

void btm_inq_remote_name_timer_timeout(void *data)
{
    btm_inq_rmt_name_failed();
}

/*******************************************************************************
**
** Function         btm_inq_rmt_name_failed
**
** Description      This function is if timeout expires while getting remote
**                  name.  This is done for devices that incorrectly do not
**                  report operation failure
**
** Returns          void
**
*******************************************************************************/
void btm_inq_rmt_name_failed(void)
{
    BTM_TRACE_ERROR("btm_inq_rmt_name_failed()  remname_active=%d", btm_cb.btm_inq_vars.remname_active);

    if(btm_cb.btm_inq_vars.remname_active)
    {
        btm_process_remote_name(btm_cb.btm_inq_vars.remname_bda, NULL, 0, HCI_ERR_UNSPECIFIED);
    }
    else
    {
        btm_process_remote_name(NULL, NULL, 0, HCI_ERR_UNSPECIFIED);
    }

    btm_sec_rmt_name_request_complete(NULL, NULL, HCI_ERR_UNSPECIFIED);
}

/*******************************************************************************
**
** Function         btm_read_inq_tx_power_timeout
**
** Description      Callback when reading the inquiry tx power times out.
**
** Returns          void
**
*******************************************************************************/
void btm_read_inq_tx_power_timeout(void *data)
{
    tBTM_CMPL_CB  *p_cb = btm_cb.devcb.p_inq_tx_power_cmpl_cb;
    btm_cb.devcb.p_inq_tx_power_cmpl_cb = NULL;

    if(p_cb)
    {
        (*p_cb)((void *) NULL);
    }
}

/*******************************************************************************
**
** Function         btm_read_inq_tx_power_complete
**
** Description      read inquiry tx power level complete callback function.
**
** Returns          void
**
*******************************************************************************/
void btm_read_inq_tx_power_complete(uint8_t *p)
{
    tBTM_CMPL_CB                *p_cb = btm_cb.devcb.p_inq_tx_power_cmpl_cb;
    tBTM_INQ_TXPWR_RESULTS        results;
    BTM_TRACE_DEBUG("%s", __func__);
    #ifdef USE_ALARM
    alarm_cancel(btm_cb.devcb.read_inq_tx_power_timer);
    #else
    btu_stop_timer(&btm_cb.devcb.read_inq_tx_power_timer);
    #endif
    btm_cb.devcb.p_inq_tx_power_cmpl_cb = NULL;

    /* If there was a registered callback, call it */
    if(p_cb)
    {
        STREAM_TO_UINT8(results.hci_status, p);

        if(results.hci_status == HCI_SUCCESS)
        {
            results.status = BTM_SUCCESS;
            STREAM_TO_UINT8(results.tx_power, p);
            BTM_TRACE_EVENT("BTM INQ TX POWER Complete: tx_power %d, hci status 0x%02x",
                            results.tx_power, results.hci_status);
        }
        else
        {
            results.status = BTM_ERR_PROCESSING;
        }

        (*p_cb)(&results);
    }
}
/*******************************************************************************
**
** Function         BTM_WriteEIR
**
** Description      This function is called to write EIR data to controller.
**
** Parameters       p_buff - allocated HCI command buffer including extended
**                           inquriry response
**
** Returns          BTM_SUCCESS  - if successful
**                  BTM_MODE_UNSUPPORTED - if local device cannot support it
**
*******************************************************************************/
tBTM_STATUS BTM_WriteEIR(BT_HDR *p_buff)
{
    if(HCI_EXT_INQ_RSP_SUPPORTED(btm_cb.devcb.local_lmp_features[HCI_EXT_FEATURES_PAGE_0]))
    {
        BTM_TRACE_API("Write Extended Inquiry Response to controller");
        btsnd_hcic_write_ext_inquiry_response(p_buff, BTM_EIR_DEFAULT_FEC_REQUIRED);
        return BTM_SUCCESS;
    }
    else
    {
        GKI_freebuf(p_buff);
        return BTM_MODE_UNSUPPORTED;
    }
}

/*******************************************************************************
**
** Function         BTM_CheckEirData
**
** Description      This function is called to get EIR data from significant part.
**
** Parameters       p_eir - pointer of EIR significant part
**                  type   - finding EIR data type
**                  p_length - return the length of EIR data not including type
**
** Returns          pointer of EIR data
**
*******************************************************************************/
uint8_t *BTM_CheckEirData(uint8_t *p_eir, uint8_t type, uint8_t *p_length)
{
    uint8_t *p = p_eir;
    uint8_t length;
    uint8_t eir_type;
    BTM_TRACE_API("BTM_CheckEirData type=0x%02X", type);
    STREAM_TO_UINT8(length, p);

    while(length && (p - p_eir <= HCI_EXT_INQ_RESPONSE_LEN))
    {
        STREAM_TO_UINT8(eir_type, p);

        if(eir_type == type)
        {
            /* length doesn't include itself */
            *p_length = length - 1; /* minus the length of type */
            return p;
        }

        p += length - 1; /* skip the length of data */
        STREAM_TO_UINT8(length, p);
    }

    *p_length = 0;
    return NULL;
}

/*******************************************************************************
**
** Function         btm_convert_uuid_to_eir_service
**
** Description      This function is called to get the bit position of UUID.
**
** Parameters       uuid16 - UUID 16-bit
**
** Returns          BTM EIR service ID if found
**                  BTM_EIR_MAX_SERVICES - if not found
**
*******************************************************************************/
static uint8_t btm_convert_uuid_to_eir_service(uint16_t uuid16)
{
    uint8_t xx;

    for(xx = 0; xx < BTM_EIR_MAX_SERVICES; xx++)
    {
        if(uuid16 == BTM_EIR_UUID_LKUP_TBL[xx])
        {
            return xx;
        }
    }

    return BTM_EIR_MAX_SERVICES;
}

/*******************************************************************************
**
** Function         BTM_HasEirService
**
** Description      This function is called to know if UUID in bit map of UUID.
**
** Parameters       p_eir_uuid - bit map of UUID list
**                  uuid16 - UUID 16-bit
**
** Returns          TRUE - if found
**                  FALSE - if not found
**
*******************************************************************************/
uint8_t BTM_HasEirService(uint32_t *p_eir_uuid, uint16_t uuid16)
{
    uint8_t service_id;
    service_id = btm_convert_uuid_to_eir_service(uuid16);

    if(service_id < BTM_EIR_MAX_SERVICES)
    {
        return(BTM_EIR_HAS_SERVICE(p_eir_uuid, service_id));
    }
    else
    {
        return(FALSE);
    }
}

/*******************************************************************************
**
** Function         BTM_HasInquiryEirService
**
** Description      This function is called to know if UUID in bit map of UUID list.
**
** Parameters       p_results - inquiry results
**                  uuid16 - UUID 16-bit
**
** Returns          BTM_EIR_FOUND - if found
**                  BTM_EIR_NOT_FOUND - if not found and it is complete list
**                  BTM_EIR_UNKNOWN - if not found and it is not complete list
**
*******************************************************************************/
tBTM_EIR_SEARCH_RESULT BTM_HasInquiryEirService(tBTM_INQ_RESULTS *p_results, uint16_t uuid16)
{
    if(BTM_HasEirService(p_results->eir_uuid, uuid16))
    {
        return BTM_EIR_FOUND;
    }
    else
        if(p_results->eir_complete_list)
        {
            return BTM_EIR_NOT_FOUND;
        }
        else
        {
            return BTM_EIR_UNKNOWN;
        }
}

/*******************************************************************************
**
** Function         BTM_AddEirService
**
** Description      This function is called to add a service in bit map of UUID list.
**
** Parameters       p_eir_uuid - bit mask of UUID list for EIR
**                  uuid16 - UUID 16-bit
**
** Returns          None
**
*******************************************************************************/
void BTM_AddEirService(uint32_t *p_eir_uuid, uint16_t uuid16)
{
    uint8_t service_id;
    service_id = btm_convert_uuid_to_eir_service(uuid16);

    if(service_id < BTM_EIR_MAX_SERVICES)
    {
        BTM_EIR_SET_SERVICE(p_eir_uuid, service_id);
    }
}

/*******************************************************************************
**
** Function         BTM_RemoveEirService
**
** Description      This function is called to remove a service in bit map of UUID list.
**
** Parameters       p_eir_uuid - bit mask of UUID list for EIR
**                  uuid16 - UUID 16-bit
**
** Returns          None
**
*******************************************************************************/
void BTM_RemoveEirService(uint32_t *p_eir_uuid, uint16_t uuid16)
{
    uint8_t service_id;
    service_id = btm_convert_uuid_to_eir_service(uuid16);

    if(service_id < BTM_EIR_MAX_SERVICES)
    {
        BTM_EIR_CLR_SERVICE(p_eir_uuid, service_id);
    }
}

/*******************************************************************************
**
** Function         BTM_GetEirSupportedServices
**
** Description      This function is called to get UUID list from bit map of UUID list.
**
** Parameters       p_eir_uuid - bit mask of UUID list for EIR
**                  p - reference of current pointer of EIR
**                  max_num_uuid16 - max number of UUID can be written in EIR
**                  num_uuid16 - number of UUID have been written in EIR
**
** Returns          BTM_EIR_MORE_16BITS_UUID_TYPE, if it has more than max
**                  BTM_EIR_COMPLETE_16BITS_UUID_TYPE, otherwise
**
*******************************************************************************/
uint8_t BTM_GetEirSupportedServices(uint32_t *p_eir_uuid,    uint8_t **p,
                                    uint8_t  max_num_uuid16, uint8_t *p_num_uuid16)
{
    uint8_t service_index;
    *p_num_uuid16 = 0;

    for(service_index = 0; service_index < BTM_EIR_MAX_SERVICES; service_index++)
    {
        if(BTM_EIR_HAS_SERVICE(p_eir_uuid, service_index))
        {
            if(*p_num_uuid16 < max_num_uuid16)
            {
                UINT16_TO_STREAM(*p, BTM_EIR_UUID_LKUP_TBL[service_index]);
                (*p_num_uuid16)++;
            }
            /* if max number of UUIDs are stored and found one more */
            else
            {
                return BTM_EIR_MORE_16BITS_UUID_TYPE;
            }
        }
    }

    return BTM_EIR_COMPLETE_16BITS_UUID_TYPE;
}

/*******************************************************************************
**
** Function         BTM_GetEirUuidList
**
** Description      This function parses EIR and returns UUID list.
**
** Parameters       p_eir - EIR
**                  uuid_size - LEN_UUID_16, LEN_UUID_32, LEN_UUID_128
**                  p_num_uuid - return number of UUID in found list
**                  p_uuid_list - return UUID list
**                  max_num_uuid - maximum number of UUID to be returned
**
** Returns          0 - if not found
**                  BTM_EIR_COMPLETE_16BITS_UUID_TYPE
**                  BTM_EIR_MORE_16BITS_UUID_TYPE
**                  BTM_EIR_COMPLETE_32BITS_UUID_TYPE
**                  BTM_EIR_MORE_32BITS_UUID_TYPE
**                  BTM_EIR_COMPLETE_128BITS_UUID_TYPE
**                  BTM_EIR_MORE_128BITS_UUID_TYPE
**
*******************************************************************************/
uint8_t BTM_GetEirUuidList(uint8_t *p_eir, uint8_t uuid_size, uint8_t *p_num_uuid,
                           uint8_t *p_uuid_list, uint8_t max_num_uuid)
{
    uint8_t   *p_uuid_data;
    uint8_t   type;
    uint8_t   yy, xx;
    uint16_t  *p_uuid16 = (uint16_t *)p_uuid_list;
    uint32_t  *p_uuid32 = (uint32_t *)p_uuid_list;
    char    buff[LEN_UUID_128 * 2 + 1];
    p_uuid_data = btm_eir_get_uuid_list(p_eir, uuid_size, p_num_uuid, &type);

    if(p_uuid_data == NULL)
    {
        return 0x00;
    }

    if(*p_num_uuid > max_num_uuid)
    {
        BTM_TRACE_WARNING("BTM_GetEirUuidList number of uuid in EIR = %d, size of uuid list = %d",
                          *p_num_uuid, max_num_uuid);
        *p_num_uuid = max_num_uuid;
    }

    BTM_TRACE_DEBUG("BTM_GetEirUuidList type = %02X, number of uuid = %d", type, *p_num_uuid);

    if(uuid_size == LEN_UUID_16)
    {
        for(yy = 0; yy < *p_num_uuid; yy++)
        {
            STREAM_TO_UINT16(*(p_uuid16 + yy), p_uuid_data);
            BTM_TRACE_DEBUG("                     0x%04X", *(p_uuid16 + yy));
        }
    }
    else
        if(uuid_size == LEN_UUID_32)
        {
            for(yy = 0; yy < *p_num_uuid; yy++)
            {
                STREAM_TO_UINT32(*(p_uuid32 + yy), p_uuid_data);
                BTM_TRACE_DEBUG("                     0x%08X", *(p_uuid32 + yy));
            }
        }
        else
            if(uuid_size == LEN_UUID_128)
            {
                for(yy = 0; yy < *p_num_uuid; yy++)
                {
                    STREAM_TO_ARRAY16(p_uuid_list + yy * LEN_UUID_128, p_uuid_data);

                    for(xx = 0; xx < LEN_UUID_128; xx++)
                    {
                        sprintf(buff + xx * 2, "%02X", *(p_uuid_list + yy * LEN_UUID_128 + xx));
                    }

                    BTM_TRACE_DEBUG("                     0x%s", buff);
                }
            }

    return type;
}


/*******************************************************************************
**
** Function         btm_eir_get_uuid_list
**
** Description      This function searches UUID list in EIR.
**
** Parameters       p_eir - address of EIR
**                  uuid_size - size of UUID to find
**                  p_num_uuid - number of UUIDs found
**                  p_uuid_list_type - EIR data type
**
** Returns          NULL - if UUID list with uuid_size is not found
**                  beginning of UUID list in EIR - otherwise
**
*******************************************************************************/
static uint8_t *btm_eir_get_uuid_list(uint8_t *p_eir, uint8_t uuid_size,
                                      uint8_t *p_num_uuid, uint8_t *p_uuid_list_type)
{
    uint8_t   *p_uuid_data;
    uint8_t   complete_type, more_type;
    uint8_t   uuid_len;

    switch(uuid_size)
    {
        case LEN_UUID_16:
            complete_type = BTM_EIR_COMPLETE_16BITS_UUID_TYPE;
            more_type     = BTM_EIR_MORE_16BITS_UUID_TYPE;
            break;

        case LEN_UUID_32:
            complete_type = BTM_EIR_COMPLETE_32BITS_UUID_TYPE;
            more_type     = BTM_EIR_MORE_32BITS_UUID_TYPE;
            break;

        case LEN_UUID_128:
            complete_type = BTM_EIR_COMPLETE_128BITS_UUID_TYPE;
            more_type     = BTM_EIR_MORE_128BITS_UUID_TYPE;
            break;

        default:
            *p_num_uuid = 0;
            return NULL;
            break;
    }

    p_uuid_data = BTM_CheckEirData(p_eir, complete_type, &uuid_len);

    if(p_uuid_data == NULL)
    {
        p_uuid_data = BTM_CheckEirData(p_eir, more_type, &uuid_len);
        *p_uuid_list_type = more_type;
    }
    else
    {
        *p_uuid_list_type = complete_type;
    }

    *p_num_uuid = uuid_len / uuid_size;
    return p_uuid_data;
}

/*******************************************************************************
**
** Function         btm_convert_uuid_to_uuid16
**
** Description      This function converts UUID to UUID 16-bit.
**
** Parameters       p_uuid - address of UUID
**                  uuid_size - size of UUID
**
** Returns          0 - if UUID cannot be converted to UUID 16-bit
**                  UUID 16-bit - otherwise
**
*******************************************************************************/
static uint16_t btm_convert_uuid_to_uuid16(uint8_t *p_uuid, uint8_t uuid_size)
{
    static const uint8_t  base_uuid[LEN_UUID_128] = {0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
                                                     0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
                                                    };
    uint16_t uuid16 = 0;
    uint32_t uuid32;
    uint8_t is_base_uuid;
    uint8_t  xx;

    switch(uuid_size)
    {
        case LEN_UUID_16:
            STREAM_TO_UINT16(uuid16, p_uuid);
            break;

        case LEN_UUID_32:
            STREAM_TO_UINT32(uuid32, p_uuid);

            if(uuid32 < 0x10000)
            {
                uuid16 = (uint16_t) uuid32;
            }

            break;

        case LEN_UUID_128:
            /* See if we can compress his UUID down to 16 or 32bit UUIDs */
            is_base_uuid = TRUE;

            for(xx = 0; xx < LEN_UUID_128 - 4; xx++)
            {
                if(p_uuid[xx] != base_uuid[xx])
                {
                    is_base_uuid = FALSE;
                    break;
                }
            }

            if(is_base_uuid)
            {
                if((p_uuid[LEN_UUID_128 - 1] == 0) && (p_uuid[LEN_UUID_128 - 2] == 0))
                {
                    p_uuid += (LEN_UUID_128 - 4);
                    STREAM_TO_UINT16(uuid16, p_uuid);
                }
            }

            break;

        default:
            BTM_TRACE_WARNING("btm_convert_uuid_to_uuid16 invalid uuid size");
            break;
    }

    return(uuid16);
}

/*******************************************************************************
**
** Function         btm_set_eir_uuid
**
** Description      This function is called to store received UUID into inquiry result.
**
** Parameters       p_eir - pointer of EIR significant part
**                  p_results - pointer of inquiry result
**
** Returns          None
**
*******************************************************************************/
void btm_set_eir_uuid(uint8_t *p_eir, tBTM_INQ_RESULTS *p_results)
{
    uint8_t   *p_uuid_data;
    uint8_t   num_uuid;
    uint16_t  uuid16;
    uint8_t   yy;
    uint8_t   type = BTM_EIR_MORE_16BITS_UUID_TYPE;
    p_uuid_data = btm_eir_get_uuid_list(p_eir, LEN_UUID_16, &num_uuid, &type);

    if(type == BTM_EIR_COMPLETE_16BITS_UUID_TYPE)
    {
        p_results->eir_complete_list = TRUE;
    }
    else
    {
        p_results->eir_complete_list = FALSE;
    }

    BTM_TRACE_API("btm_set_eir_uuid eir_complete_list=0x%02X", p_results->eir_complete_list);

    if(p_uuid_data)
    {
        for(yy = 0; yy < num_uuid; yy++)
        {
            STREAM_TO_UINT16(uuid16, p_uuid_data);
            BTM_AddEirService(p_results->eir_uuid, uuid16);
        }
    }

    p_uuid_data = btm_eir_get_uuid_list(p_eir, LEN_UUID_32, &num_uuid, &type);

    if(p_uuid_data)
    {
        for(yy = 0; yy < num_uuid; yy++)
        {
            uuid16 = btm_convert_uuid_to_uuid16(p_uuid_data, LEN_UUID_32);
            p_uuid_data += LEN_UUID_32;

            if(uuid16)
            {
                BTM_AddEirService(p_results->eir_uuid, uuid16);
            }
        }
    }

    p_uuid_data = btm_eir_get_uuid_list(p_eir, LEN_UUID_128, &num_uuid, &type);

    if(p_uuid_data)
    {
        for(yy = 0; yy < num_uuid; yy++)
        {
            uuid16 = btm_convert_uuid_to_uuid16(p_uuid_data, LEN_UUID_128);
            p_uuid_data += LEN_UUID_128;

            if(uuid16)
            {
                BTM_AddEirService(p_results->eir_uuid, uuid16);
            }
        }
    }
}

/*******************************************************************************
**
** Function         BTM_IsScanActive
**
** Description      This function returns a bit mask of the current scan active
**
** Returns          BTM_LE_SELECT_CONN_ACTIVE      0x40
**                  BTM_LE_OBSERVE_ACTIVE          0x80               
**
*******************************************************************************/
uint8_t BTM_IsBleScanActive(void)
{
    BTM_TRACE_API("BTM_IsInquiryActive");
	#if BLE_INCLUDED == TRUE
    return BTM_BLE_IS_SCAN_ACTIVE(btm_cb.ble_ctr_cb.scan_activity);
	#else
	return 0x00;
	#endif
}
/*******************************************************************************
**
** Function         BTM_IsAdvertiseActive
**
** Description      This function returns ble controller is advertising or not
**
** Returns          BTM_BLE_ADV_ENABLE                  1
**                  otherwise                           0               
**
*******************************************************************************/

uint8_t BTM_IsBleAdvertiseActive(void)
{
	BTM_TRACE_API("BTM_IsAdvertiseActive");
	#if BLE_INCLUDED == TRUE
	return (btm_cb.ble_ctr_cb.inq_var.adv_mode);
	#else
	return 0x00;
	#endif
}


